home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / benchmarks / itc / sld / sld.c < prev   
Encoding:
C/C++ Source or Header  |  1989-08-30  |  81.1 KB  |  3,108 lines

  1. /* $Header: sld.c,v 2.26 88/10/02 16:46:55 hilfingr Exp $ */
  2.  
  3. /*         SPUR Loader                 */
  4.  
  5. /* Copyright (C) 1987 by the Regents of the University of California.  All 
  6.  * rights reserved.
  7.  *
  8.  * Author: P. N. Hilfinger
  9.  */
  10.  
  11. static char *rcsid = "$Header: sld.c,v 2.26 88/10/02 16:46:55 hilfingr Exp $";
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <sys/file.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <ar.h>
  19. #include <ranlib.h>
  20. #include "a.out.h"
  21.  
  22.            /* System parameters */
  23.  
  24. #define MAXLOADFILES     300    /* Maximum number of files that may be 
  25.                  * loaded together */
  26. #define GLOBALHASHSIZE    2053    /* Size of hash table for global 
  27.                  * symbols (prime) */
  28. #define MAXEXPRSYLS      100    /* Maximum number of syllables in a relocation 
  29.                  * expression */
  30. #define MAXFILENAMESIZE 100
  31.  
  32.            /* Various constants */
  33. #define TRUE    1
  34. #define FALSE    0
  35.  
  36. #define SCONSLOWMASK  0x000001ff
  37. #define SCONSHIGHMASK 0x01f00000
  38. #define SCONSMASK     (SCONSLOWMASK | SCONSHIGHMASK)
  39. #define SCONSHIGHPOSN 20
  40. #define SCONSLOWLEN   9
  41.  
  42.     /* Masks, etc.,  corresponding to bits indicated by RP_LOW8, ..., RP_32 */
  43. static unsigned int lengthBitMask[] = {
  44.     0xff, 0x1ff, 0x3fff, 0xffff, 0x01f001ff, 0x0fffffff, 0xffffffff };
  45.  
  46.     /* Numbers of bits affected by each of RP_LOW8, etc.   RP_LOW28 is a
  47.      * special case, not covered by this table.  
  48.      */
  49. static unsigned int lengthMap[] = {
  50.     8, 9, 14, 16, 14, 0, 32 
  51.     };
  52.  
  53.     /* Maximum and minimum values for fields.  See comment on RP_LOW28
  54.      * above. The values for LOW8 and
  55.      * LOW16 are chosen to allow any valid 16-bit 2's complement
  56.      * signed integer or 16-bit unsigned integer.
  57.      */
  58. static unsigned int minMap[] = {
  59.     -(1<<7), -(1<<8), -(1<<13), -(1<<15), -(1<<13), 0, -(1<<31)
  60.     };
  61. static unsigned int maxMap[] = {
  62.     (1<<8)-1, (1<<8)-1, (1<<13)-1, (1<<16)-1, (1<<13)-1, 0, (1<<31)-1
  63.     };
  64.  
  65.     /* Additional load file inquiries */
  66.  
  67.                 /* Given address after text and magic */
  68.                 /* number, the beginning of private data. */
  69.                 /* WARNING: SHOULD REALLY BE IN a.out.h */
  70. #define DATA_ADDR(textEnd,magic) \
  71.     ((magic) == ZMAGIC ? 0xc0000000 : (textEnd))
  72.  
  73.                 /* Length of actual text (excluding */
  74.                 /* header) in file with given header. */
  75.                 /* WARNING: SHOULD REALLY BE IN a.out.h */
  76. #define REAL_TEXT_LENGTH(header) \
  77.     ((header).a_magic == ZMAGIC ? (header).a_text - sizeof(struct exec) \
  78.      : (header).a_text)
  79.  
  80.     /* Standard load libraries */
  81.  
  82. static char *standardLibs[] = 
  83. {
  84.     "/lib/", "/usr/lib/", "/usr/local/lib/", NULL
  85.     };
  86.  
  87.         /* Data structures */
  88.  
  89. typedef int bool;
  90.  
  91. struct _globalSymType {        /* Serve as unique representatives for global 
  92.                    symbols */
  93.     char     *name;        /* External identifier */
  94.     int        file;        /* Index of load file of representative 
  95.                    instance. */
  96.     struct nlist *sym;        /* Representative instance (redundant). */
  97.     struct _globalSymType
  98.             *link;        /* Link for hash table. */
  99.     struct _globalSymType
  100.             *nextUnresolved, *lastUnresolved;
  101.                 /* Links for list of unresolved references. */
  102. };
  103.  
  104. typedef struct _globalSymType    globalSymType;
  105.  
  106.        /* Forwarding pointer for symbols */
  107. #define globalReferent(sym)     (*((globalSymType **) &((sym) -> n_un.n_strx)))
  108.  
  109.                 /* Values for r_extra field in struct relocation_infos. */
  110. #define RELOC_DONE      1    /* No further relocation needed. */
  111. #define RELOC_EXCLUDE   2    /* No further relocation needed and the 
  112.                  * relocation
  113.                  * item need not be retained for future 
  114.                  * relocations */
  115.  
  116.                 /* Values for n_other fields */
  117. #define SYM_USED        1    /* Symbol used for relocation */
  118. #define SYM_EXCLUDE     2       /* Symbol to be thrown out */
  119.  
  120.         /* Global objects */
  121.  
  122. static char *programName;    /* Argument 0 to program. */
  123.  
  124. static int errorCount;
  125.  
  126. static struct exec aHeader;    /* Handy header (put here to avoid lint
  127.                  * hassles) */
  128.  
  129. static globalSymType     *globals[GLOBALHASHSIZE];    
  130.                 /* Hash table for global symbols */
  131. static globalSymType    unresolvedSyms =
  132.      { NULL, 0, NULL, NULL, 0, 0};
  133.                 /* Header for list of unresolved symbols */
  134. static struct exec    fileHeader[MAXLOADFILES];
  135.                 /* The headers for the loaded files. */
  136. static struct nlist      *fileDefns[MAXLOADFILES];
  137.                 /* The symbol tables of the loaded files. */
  138. static struct relocation_info
  139.                         *fileRelocs[MAXLOADFILES];
  140.                                 /* The relocation data for the loaded files. */
  141. static char         *fileStrings[MAXLOADFILES],
  142.                 /* String areas for the loaded files. */
  143.                         *fileName[MAXLOADFILES];
  144.  
  145. static union reloc_expr *fileRelocExprs[MAXLOADFILES];
  146.                 /* Relocation expressions for the loaded 
  147.                  * files. */
  148. static unsigned int
  149.                 /* Starts of text and data areas for the loaded
  150.                    files. */
  151.             *fileText[MAXLOADFILES],
  152.             *fileData[MAXLOADFILES],
  153.                         *fileSData[MAXLOADFILES],
  154.  
  155.                 /* Load addresses for the segments of each 
  156.                    file. */
  157.                         fileTextAddr[MAXLOADFILES],
  158.                         fileDataAddr[MAXLOADFILES],
  159.                         fileSDataAddr[MAXLOADFILES],
  160.                         fileBssAddr[MAXLOADFILES],
  161.                         fileSBssAddr[MAXLOADFILES],
  162.                                 /* Amount segment relocated, indexed by file 
  163.                    and n_type. */
  164.                         fileDelta[MAXLOADFILES][N_SBSS + 1];
  165. static unsigned  int numFiles;    /* Number of object files */
  166.  
  167. static int EOtoNmap[EO_SBSS+1]; /* Maps EO_TEXT, ... to N_TEXT, ... */
  168.  
  169.                 /* Command line switches */
  170.  
  171. static bool
  172.     dSwitch,
  173.     MSwitch,
  174.     pdSwitch,
  175.     ptSwitch,
  176.     rSwitch,
  177.     sSwitch,
  178.     SSwitch,
  179.     tSwitch,
  180.     TtextSwitch,        /* -T or -Ttext present */
  181.     TdataSwitch,
  182.     TsdataSwitch,
  183.     wSwitch,
  184.     xSwitch,
  185.     XSwitch;
  186.  
  187. static char *baseFileName;    /* From -A option */
  188. static char *outFileName;    /* From -o option */
  189. static int magic;        /* Magic number for file */
  190. static char *entryName;        /* From -e option */
  191.  
  192. static unsigned int textStart;    /* Text starting address. */
  193. static unsigned int dataStart;    /* Data starting address from -Tdata; defined
  194.                 /* only if TdataSwitch. */
  195. static unsigned int sdataStart; /* Shared data starting address from -Tsdata;
  196.                 /* defined only if TsdataSwitch */
  197. static char **dirList;        /* Vector of names from -L option (ended by
  198.                  * null pointer) */
  199. static char **tracedSyms;    /* Vector of names from -y options (ended by
  200.                  * null pointer) */
  201. static struct nlist *forcedSyms;
  202.                                 /* Vector of names from -u options (ended by
  203.                  * null pointer) */
  204. static unsigned int numForcedSyms, numTracedSyms;
  205.  
  206.             /* Forward declarations */
  207. extern int
  208.     hash(),
  209.     readOpenObjectFile(),
  210.     exprLength(),
  211.     indirectStrcmp(),
  212.     ranlibCompare();
  213.  
  214. extern bool
  215.     matchPhrase(),
  216.     evalReloc();
  217.  
  218. extern unsigned int
  219.     evalConstUnaryExpr(),
  220.     evalConstBinaryExpr(),
  221.     evalSym(),
  222.     segmentOffsetToNewAddr(),
  223.     evalLoadExpr(),
  224.     extractVal();
  225.  
  226. extern unsigned char
  227.     *relocSegmentToPntr();
  228.  
  229. extern globalSymType
  230.     **findSymbolEntry();
  231.  
  232. extern void
  233.     realSym(),
  234.     internSym(),
  235.     convertStringIndex(),
  236.     convertStringIndicies(),
  237.     insertVal(),
  238.     computeRelocations(),
  239.     resolveCommon(),
  240.     setLoc(),
  241.     incrLoc(),
  242.     readOpenLibraryFile(),
  243.     setupForcedSyms(),
  244.     setupBaseFile(),
  245.     relocateAll(),
  246.     relocSizes(),
  247.     relocateSymbols(),
  248.     computeEnds(),
  249.     relocateExprs(),
  250.     countAndMarkSymbols(),
  251.     createNewSymbolsAndStrings(),
  252.     createNewRelocs(),
  253.     writeObjectFile(),
  254.     writeCombinedFile();
  255.  
  256. extern union reloc_expr
  257.     *simpLoadExpr(),
  258.     *simpCanonLoadExpr(),
  259.     *reduceExpr(),
  260.     *compressExpr(),
  261.     *createNewRelocExpr();
  262.  
  263. extern char
  264.     *bsearch(),
  265.     *calloc(),
  266.     *malloc();
  267.  
  268. extern long
  269.     lseek();
  270.  
  271.         /* Various utilities */
  272.  
  273. void
  274. printErrorHeader()
  275. {
  276.     (void) fprintf(stderr, "%s: ", programName);
  277. }
  278.  
  279. #define ErrorMsg    {\
  280.     printErrorHeader(); \
  281.     (void) fprintf(stderr, 
  282.  
  283. #define EndMsg     \
  284.     );  \
  285.     (void) putc('\n', stderr); \
  286.     errorCount += 1; \
  287.     errorBreak();\
  288.  }
  289.  
  290. #define FormatError { \
  291.     ErrorMsg "Format error in load file." EndMsg; \
  292.     exit(1); \
  293.     }
  294.  
  295. #define InternalError { \
  296.     ErrorMsg "Internal loader error." EndMsg; \
  297.     exit(1); \
  298.     }
  299.  
  300. #define InsufficientSpace  { \
  301.     ErrorMsg  "Insufficient memory to build load file." EndMsg; \
  302.     exit(1); \
  303.     }
  304.  
  305. void
  306. errorBreak()
  307. {
  308. }
  309.  
  310.          /* Result of incrementing  pointer by byte offset */
  311. #define BINCR(p, offset, type) ((type *) ((int) (p) + (int) (offset)))
  312.  
  313.          /* Byte address difference between two pointers */
  314. #define BDIFF(p1, p2) ((int) (p1) - (int) (p2))
  315.  
  316.  
  317.         /* Resolving global symbols */
  318.  
  319. void
  320. realSym(inSym, inFile, outSym, outFile)
  321.      struct nlist *inSym, **outSym;
  322.      unsigned int inFile, *outFile;
  323.      /* For any symbol inSym, returns the "real" definition of sym in *outSym,
  324.       * i.e., either *inSym itself, or, in the case of an external definition,
  325.       * the global defining instance of *inSym. The number of the file 
  326.       * containing inSym must be passed as inFile if inSym is not an 
  327.       * external reference; otherwise it is ignored.  The variable *outFile is
  328.       * set to the number of the file containing *outSym.  */
  329. {
  330.     switch (inSym -> n_type & N_TYPE) {
  331.     case N_UNDF:
  332.     case N_COMM:
  333.     case N_SCOMM: {
  334.     globalSymType *g = globalReferent(inSym);
  335.     *outSym = g -> sym;
  336.     *outFile = g -> file;
  337.     break;
  338.     }
  339.     default:
  340.     *outSym = inSym;
  341.     *outFile = inFile;
  342.     break;
  343.     }
  344. }
  345.  
  346. char *
  347. symName(sym)
  348.      struct nlist *sym;
  349.      /* Identifier associated with sym. */
  350. {
  351.     switch (sym -> n_type) {
  352.     case N_UNDF | N_EXT:
  353.     case N_UNDF:
  354.     case N_COMM | N_EXT:
  355.     case N_SCOMM | N_EXT:
  356.     return globalReferent(sym) -> name;
  357.     default:
  358.     return sym -> n_un.n_name;
  359.     }
  360. }    
  361.  
  362. int
  363. hash(s)
  364.      char *s;
  365.      /* Compute a hash value from s in the range 0 .. GLOBALHASHSIZE-1. */
  366.      /* Taken from P. J. Weinberger, as published in Aho, Sethi, Ullman. */
  367. {
  368.     char *p;
  369.     unsigned h = 0, g;
  370.  
  371.     for (p = s; *p != '\0'; p++) {
  372.     h = (h << 4) + *p;
  373.         g = h & 0xf0000000;
  374.     if (g != 0)
  375.         h ^= (g >> 24) ^ g;
  376.     }
  377.     return (int) (h % GLOBALHASHSIZE);
  378. }
  379.  
  380. globalSymType **
  381. findSymbolEntry(str)
  382.      char *str;
  383.      /* Reference to a variable containing the current representative entry, 
  384.       * if any, for str, or NULL if none.   This variable may be set to a
  385.       * new entry to add a symbol.  */
  386. {
  387.     globalSymType **rep;
  388.  
  389.     for (rep = &globals[hash(str)]; 
  390.      *rep != NULL && strcmp((*rep) -> name, str) != 0;
  391.      rep = &((*rep) -> link));
  392.     return rep;
  393. }
  394.  
  395. void
  396. internSym(sym, file)
  397.      unsigned int file;
  398.      struct nlist *sym;
  399.      /* Where *sym is a symbol definition in object file number file, with
  400.       * the n_un.n_name field valid.
  401.       * If sym is a global definition:
  402.       *     1. Check that sym is not multiply defined and report if it is.
  403.       *        2. If (1) succeeds, establish sym as the defining instance for the
  404.       *        symbol it contains.  If (1) fails, change sym to an external 
  405.       *           reference to the previous definition (see (3) below).
  406.       * If sym is an external reference or .comm symbol:
  407.       *     3. Set globalReferent(sym) to a globalSymType unique to that 
  408.       *        symbol.
  409.       *     4. If this is the first encounter of sym, make sym the 
  410.       *           representative instance.  Also, if the symbol is a .comm symbol,
  411.       *        and all previous references have been external references or 
  412.       *        .comm symbols with smaller space requests, make this 
  413.       *        the representative instance.
  414.       * Assumes that the n_un.n_name field is initially valid.
  415.       */
  416. {
  417.     char *str = sym -> n_un.n_name;
  418.     globalSymType *rep, **prep;
  419.     int type = sym -> n_type;
  420.     int stype = type & N_TYPE;
  421.  
  422.     if ((type & N_STAB) != 0 || (type & N_EXT) == 0)
  423.     return;
  424.  
  425.     if (str[0] == '\0') {
  426.     ErrorMsg "Global or external symbol (#%d) with null name in %s.", 
  427.              sym - fileDefns[file], fileName[file]
  428.     EndMsg;
  429.     return;
  430.     }
  431.     
  432.     prep = findSymbolEntry(str);
  433.     rep = *prep;
  434.  
  435.     if (rep == NULL) {
  436.     rep = (globalSymType *) malloc(sizeof(globalSymType));
  437.     rep -> name = str;
  438.     rep -> file = file;
  439.     rep -> sym = sym;
  440.     rep -> link = NULL;
  441.     *prep = rep;
  442.  
  443.     if (stype == N_UNDF) {
  444.         rep -> nextUnresolved = unresolvedSyms.nextUnresolved;
  445.         rep -> lastUnresolved = &unresolvedSyms;
  446.         rep -> nextUnresolved -> lastUnresolved = rep;
  447.         rep -> lastUnresolved -> nextUnresolved = rep;
  448.     }
  449.     else rep -> nextUnresolved = rep -> lastUnresolved = NULL;
  450.     }
  451.     else {
  452.     int oldstype = (rep -> sym -> n_type) & N_TYPE;
  453.     if ((type & N_EXT) != 0 && 
  454.         stype != N_UNDF && stype != N_COMM && stype != N_SCOMM &&
  455.         oldstype != N_UNDF && oldstype != N_COMM && oldstype != N_SCOMM) {
  456.         ErrorMsg "Global symbol %s defined in %s and %s.", 
  457.                str, fileName[rep -> file], fileName[file]
  458.         EndMsg;
  459.         sym -> n_type = N_EXT | N_UNDF;
  460.         globalReferent(sym) = rep;
  461.     }
  462.     }
  463.  
  464.     switch (type & N_TYPE) {
  465.  
  466.     case N_UNDF:
  467.     globalReferent(sym) = rep;
  468.     break;
  469.  
  470.     case N_COMM:
  471.     case N_SCOMM:
  472.     globalReferent(sym) = rep;
  473.     switch (rep -> sym -> n_type & N_TYPE) {
  474.     case N_UNDF:
  475.         rep -> file = file, rep -> sym = sym;
  476.         break;
  477.     case N_COMM:
  478.     case N_SCOMM:
  479.         if ((rep -> sym -> n_type & N_TYPE) != (type & N_TYPE)) {
  480.         ErrorMsg "Conflicting definitions of common region %s.", str
  481.             EndMsg;
  482.         sym -> n_type = rep -> sym -> n_type;
  483.         }
  484.         if (sym -> n_value > rep -> sym -> n_value)
  485.         rep -> file = file, rep -> sym = sym;
  486.         break;
  487.     default:
  488.         break;
  489.     }
  490.     if (rep -> nextUnresolved != NULL) {
  491.         rep -> nextUnresolved -> lastUnresolved = rep -> lastUnresolved;
  492.         rep -> lastUnresolved -> nextUnresolved = rep -> nextUnresolved;
  493.         rep -> lastUnresolved = rep -> nextUnresolved = NULL;
  494.     }
  495.     break;
  496.  
  497.     default:
  498.     rep -> file = file;
  499.     rep -> sym = sym;
  500.     if (rep -> nextUnresolved != NULL) {
  501.         rep -> nextUnresolved -> lastUnresolved = rep -> lastUnresolved;
  502.         rep -> lastUnresolved -> nextUnresolved = rep -> nextUnresolved;
  503.         rep -> lastUnresolved = rep -> nextUnresolved = NULL;
  504.     }
  505.     break;
  506.     }
  507. }
  508.  
  509. void
  510. convertStringIndex(sym,file)
  511.      struct nlist *sym;
  512.      unsigned int file;
  513. {
  514.     if (sym -> n_un.n_strx == 0)
  515.     sym -> n_un.n_name = "";
  516.     else 
  517.     sym -> n_un.n_name = fileStrings[file] + sym -> n_un.n_strx;
  518. }
  519.  
  520. void
  521. convertStringIndices(file)
  522.      unsigned int file;
  523.      /* Convert n_strx fields for all symbols in file number file to string
  524.       * pointers. */
  525. {
  526.     struct nlist
  527.     *last = (struct nlist *) ((int) fileDefns[file] + 
  528.                   fileHeader[file].a_syms),
  529.     *sym;
  530.     for (sym = fileDefns[file]; sym != last; sym++) {
  531.     convertStringIndex(sym,file);
  532.     }
  533. }
  534.  
  535. void
  536. internAllSyms(file)
  537.      unsigned int file;
  538.      /* Intern all symbols in object file number file. Assumes that all
  539.       * string indices have been replaced by strings in the symbols for
  540.       * file. */
  541. {
  542.     struct nlist
  543.     *last = (struct nlist *) ((int) fileDefns[file] + 
  544.                   fileHeader[file].a_syms),
  545.     *sym;
  546.     for (sym = fileDefns[file]; sym != last; sym++) {
  547.     if (numTracedSyms > 0 && file != 0 
  548.         && bsearch((char *) (&sym -> n_un.n_name), (char *) tracedSyms, 
  549.                numTracedSyms, sizeof(char *),
  550.                indirectStrcmp) != (char *) NULL ) {
  551.  
  552.         int stype = sym -> n_type & N_TYPE;
  553.         char *name = sym -> n_un.n_name;
  554.  
  555.         (void) printf("%s: ", fileName[file]);
  556.  
  557.         switch (stype) {
  558.         case N_UNDF:
  559.         (void) fputs("reference to ", stdout);
  560.         break;
  561.         default:
  562.         (void) fputs("definition of ", stdout);
  563.         break;
  564.         }
  565.         
  566.         if (stype == N_COMM) 
  567.         (void) printf("common %s size %d\n", name, sym -> n_value);
  568.         else if (stype == N_SCOMM)
  569.         (void) printf("shared common %s size %d\n", name, 
  570.                   sym -> n_value);
  571.         else {
  572.         if (sym -> n_type & N_EXT)
  573.             (void) fputs("external ", stdout);
  574.  
  575.         (void) printf("%s %s\n",
  576.                   stype == N_UNDF ? "undefined " :
  577.                   stype == N_TEXT ? "text " :
  578.                   stype == N_DATA ? "data " :
  579.                   stype == N_BSS ? "bss " :
  580.                   stype == N_SDATA ? "shared data " :
  581.                   stype == N_SBSS ? "shared bss " :
  582.                   "?", name);
  583.         }
  584.     }
  585.     internSym(sym, file);
  586.     }
  587. }
  588.  
  589.              /* Expression simplification and evaluation */
  590.  
  591. int
  592. exprLength(e)
  593.      union reloc_expr *e;
  594.      /* The length in words of e.  (Also checks the validity of the 
  595.       * expression.) */
  596. {
  597.     switch (e -> re_syl.re_op) {
  598.     case EO_INT:
  599.     case EO_SYM:
  600.     case EO_TEXT:
  601.     case EO_DATA:
  602.     case EO_BSS:
  603.     return 2;
  604.     case EO_MINUS:
  605.     case EO_COMP:
  606.     return 1 + exprLength(e+1);
  607.     case EO_PLUS:
  608.     case EO_MULT:
  609.     case EO_DIV:
  610.     case EO_SLL:
  611.     case EO_SRL:
  612.     case EO_AND:
  613.     case EO_OR:
  614.     case EO_XOR:
  615.     case EO_SUB:
  616.     {
  617.         int L1 = exprLength(e+1);
  618.         return L1 + 1 + exprLength(e+L1+1);
  619.     }
  620.     default:
  621.     FormatError;     /*NOTREACHED*/
  622.     }
  623. }    
  624.  
  625. unsigned int
  626. evalConstUnaryExpr(op, left)
  627.      unsigned int op, left;
  628.      /* Evaluate expression `op left', where op is an re_op.  */
  629. {
  630.     switch (op) {
  631.     case EO_MINUS:
  632.     return  -left;
  633.     case EO_COMP:
  634.     return ~left;
  635.     default:
  636.     InternalError;      /*NOTREACHED*/
  637.     }
  638. }
  639.  
  640. unsigned int
  641. evalConstBinaryExpr(op, left, right)
  642.      unsigned int op, left, right;
  643.      /* Evaluate expression `left op right', where op is an re_op. */
  644. {
  645.     switch (op) {
  646.     case EO_PLUS:
  647.     return left + right;
  648.     case EO_MULT:
  649.     return left  * right;
  650.     case EO_DIV:
  651.     if (right != 0) return left / right;
  652.     else {
  653.         ErrorMsg  "Division by zero in load-time expression." EndMsg;
  654.         return 0;
  655.     }
  656.     case EO_SLL:
  657.     return left << right;
  658.     case EO_SRL:
  659.     return left >> right;
  660.     case EO_AND:
  661.     return left & right;
  662.     case EO_OR:
  663.     return left | right;
  664.     case EO_XOR:
  665.     return left ^ right;
  666.     case EO_SUB:
  667.     return left - right;
  668.     default:
  669.     FormatError;     /*NOTREACHED*/
  670.     }
  671. }
  672.  
  673. unsigned int
  674. evalSym(e, file, defined)
  675.      union reloc_expr *e;
  676.      unsigned int file;
  677.      bool *defined;
  678.      /* Given expression e consisting of a symbol, appearing in given file,
  679.       * returns its value, if defined.  Sets *defined to TRUE iff value
  680.       * defined.  If *defined FALSE, return value is undefined. */
  681. {
  682.     struct nlist *sym;
  683.     unsigned int symFile;
  684.  
  685.     realSym(fileDefns[file] + e -> re_syl.re_arg, file, &sym, &symFile);
  686.  
  687.     *defined = TRUE;
  688.     switch (sym -> n_type & N_TYPE) {
  689.     case N_ABS:
  690.     case N_EXPR:
  691.     return (sym -> n_value + e[1].re_value);
  692.     case N_TEXT:
  693.     case N_DATA:
  694.     case N_SDATA:
  695.     case N_BSS:
  696.     case N_SBSS:
  697.     return (sym -> n_value + e[1].re_value);
  698.     default:
  699.     *defined = FALSE;
  700.     
  701.     return 0;
  702.     }
  703. }
  704.  
  705. unsigned int
  706. evalLoadExpr(e, file, defined)
  707.      union reloc_expr *e;
  708.      unsigned int file;
  709.      bool *defined;
  710.      /* Given load expression e appearing in given load file, returns its
  711.       * value if defined, and sets *defined to TRUE.  Otherwise, sets
  712.       * *defined to FALSE, and returns an undefined value. */
  713. {
  714.     unsigned int op1, op2;
  715.     bool defined1;
  716.     *defined = TRUE;
  717.     switch (e -> re_syl.re_op) {
  718.     case EO_INT:
  719.     return e[1].re_value;
  720.     case EO_SYM:
  721.     return evalSym(e, file, defined);
  722.     case EO_TEXT:
  723.     return fileTextAddr[file] + e[1].re_value;
  724.     case EO_DATA:
  725.     return fileDataAddr[file] + e[1].re_value;
  726.     case EO_BSS:
  727.     return fileBssAddr[file] + e[1].re_value;
  728.     case EO_MINUS:
  729.     case EO_COMP:
  730.     op1 = evalLoadExpr(e+1, file, defined);
  731.     if (*defined)
  732.         return evalConstUnaryExpr(e -> re_syl.re_op, op1);
  733.     else return 0;
  734.     default:         /* Binary expression */
  735.     op1 = evalLoadExpr(e+1, file, &defined1);
  736.     op2 = evalLoadExpr(e+exprLength(e+1)+1, file, defined);
  737.     if (!defined1) *defined = FALSE;
  738.     if (*defined) {
  739.         if (*defined)
  740.         return evalConstBinaryExpr(e -> re_syl.re_op, op1, op2);
  741.     }
  742.     return 0;
  743.     }
  744. }
  745.  
  746. union reloc_expr *
  747. simpLoadSym(e, file)
  748.      union reloc_expr *e;
  749.      unsigned int file;
  750.      /* Given e in file with index file consisting of a symbol reference to s,
  751.       * return expression for definition of s.  May change *e.  */
  752. {
  753.     struct nlist *sym;
  754.     unsigned int realFile;
  755.     unsigned int type;
  756.  
  757.     realSym(fileDefns[file] + e -> re_syl.re_arg, file, &sym, &realFile);
  758.  
  759.     type = sym -> n_type & N_TYPE;
  760.     switch (type) {
  761.     case N_UNDF:
  762.     case N_COMM:
  763.     case N_SCOMM:
  764.     case N_EXPR:
  765.     return e;
  766.     case N_ABS:
  767.     EO_SET_SYL2(*e, EO_INT, 0);
  768.     e[1].re_value += sym -> n_value;
  769.     return e;
  770.     case N_TEXT:
  771.     case N_DATA:
  772.     case N_SDATA:
  773.     case N_BSS:
  774.     case N_SBSS:
  775.     EO_SET_SYL2(*e,
  776.             type == N_TEXT ? EO_TEXT :
  777.             type == N_DATA ? EO_DATA :
  778.             type == N_BSS ? EO_BSS :
  779.             type == N_SDATA ? EO_SDATA :
  780.             /* else */   EO_SBSS,
  781.             0);
  782.     e[1].re_value += sym -> n_value;
  783.     return e;
  784.     default:
  785.     FormatError;     /*NOTREACHED*/
  786.     }
  787. }
  788.  
  789. union reloc_expr *
  790. simpLoadExpr(e, file)
  791.      union reloc_expr *e;
  792.      unsigned int file;
  793.      /* Simplify the expression e from object file with index file in place,
  794.       * returning the address of the result.
  795.       */
  796. {
  797.     union reloc_expr *simp1, *simp2;    /* Simplified operands. */
  798.     int len1;                /* Length of first operand */
  799.     unsigned int op;            /* Operator */
  800.     
  801.          /* Simplify operands, check for base cases */
  802.     op = e -> re_syl.re_op;
  803.     switch(op) {
  804.     case EO_INT:
  805.     case EO_TEXT:
  806.     case EO_DATA:
  807.     case EO_BSS:
  808.     case EO_SDATA:
  809.     case EO_SBSS:
  810.     return e;
  811.     case EO_SYM:
  812.     return simpLoadSym(e, file);
  813.     case EO_MINUS:
  814.     case EO_COMP:
  815.     simp1 = simpLoadExpr(e+1, file);
  816.     if (simp1 -> re_syl.re_op == EO_INT) {
  817.         simp1[1].re_value = evalConstUnaryExpr(op, simp1[1].re_value);
  818.         return simp1;
  819.     }
  820.     simp2 = NULL;
  821.     break;
  822.     default:    /* Binary operator */
  823.     len1 = exprLength(e+1);
  824.     simp1 = simpLoadExpr(e+1, file);
  825.     simp2 = simpLoadExpr(e+len1+1, file);
  826.     if (simp1 -> re_syl.re_op == EO_INT && simp2 -> re_syl.re_op == EO_INT) {
  827.         simp1[1].re_value = 
  828.         evalConstBinaryExpr(op,simp1[1].re_value, simp2[1].re_value);
  829.         return simp1;
  830.     }
  831.     }
  832.  
  833.     return simpCanonLoadExpr(e, simp1, simp2);
  834. }
  835.  
  836. /* Mini-pattern matching facility */
  837.  
  838. /* Patterns are sequences of words, interpreted as subsets of the set
  839.  * containing the EO_xxx operators, DONT_CARE, EQ_P0, SET_P0, ZERO,
  840.  * ONE, and STOP.  An expression syllable matches such a word if the
  841.  * word contains DONT_CARE, if the operator part of the syllable is
  842.  * one of the EO_xxx operators in the set, if register P0 is equal to
  843.  * the syllable and EQ_P0 is in the set, if the syllable is 0 and ZERO
  844.  * is in the set, or if the syllable is 1 and ONE is in the set.  If
  845.  * SET_P0 is in the set, then P0 is set to the current syllable.  If
  846.  * STOP is in the set, then pattern matching ends with this word.
  847.  */
  848.  
  849. #define DONT_CARE    0x80000000
  850. #define EQ_P0        0x40000000
  851. #define SET_P0       0x20000000
  852. #define STOP      0x10000000
  853. #define ZERO         0x08000000
  854. #define ONE         0x04000000
  855. #define OP         1 <<
  856.  
  857. #define SYM_OR_SEG  OP EO_TEXT | OP EO_DATA | OP EO_BSS | OP EO_SYM \
  858.                     | OP EO_SDATA | OP EO_SBSS
  859. #define PLUS_MINUS  OP EO_PLUS | OP EO_MINUS
  860.  
  861. static unsigned int simpPatterns[][12] =
  862.     {  {OP EO_PLUS | OP EO_MULT | STOP,   STOP,  OP EO_INT | STOP},
  863.        /* 1: any +* const */
  864.        {OP EO_SUB | STOP,   DONT_CARE | STOP,   OP EO_INT | STOP},
  865.        /* 2: any - const */
  866.        {OP EO_PLUS | STOP,  OP EO_INT | STOP,  SYM_OR_SEG | STOP},
  867.        /* 3: const + sym */
  868.        {OP EO_SUB | STOP,  SYM_OR_SEG | SET_P0 | STOP,  EQ_P0 | STOP},
  869.        /* 4: sym - same */
  870.        {OP EO_MULT | STOP, OP EO_INT, ZERO | STOP, DONT_CARE | STOP},
  871.        /* 5: 0 * any */
  872.        {OP EO_PLUS | STOP, OP EO_INT, ZERO | STOP, DONT_CARE | STOP},    
  873.        /* 6: 0 + any */
  874.        {OP EO_MULT | STOP, OP EO_INT, ONE | STOP, DONT_CARE | STOP},
  875.        /* 7: 1 * any */
  876.        {OP EO_SUB | STOP, OP EO_INT, ZERO | STOP, DONT_CARE | STOP},
  877.        /* 8: 0 - any */
  878.        {OP EO_MINUS | STOP, OP EO_MINUS | STOP, DONT_CARE | STOP},
  879.        /* 9: - -any */
  880.        {OP EO_PLUS | STOP, DONT_CARE | STOP, EO_MINUS | STOP},
  881.        /* 10: x + -y */
  882.        {OP EO_PLUS | STOP, EO_MINUS | STOP, DONT_CARE | STOP},
  883.        /* 11: -x + y */
  884.        {OP EO_SUB | STOP, DONT_CARE | STOP, EO_MINUS | STOP},
  885.        /* 12: x - -y */
  886.        {STOP} };
  887.                  
  888. union reloc_expr *
  889. simpCanonLoadExpr(e, opnd1, opnd2)
  890.      union reloc_expr *e, *opnd1, *opnd2;
  891.      /* Given unary or binary expression with operator in e and
  892.       * operands in opnd1 and opnd2, return simplified expression.
  893.       * Assume opnd1 and opnd2 are simplified and compressed
  894.       * expressions (results are also).  Modifies original
  895.       * expressions. It is assumed that the operands are not both
  896.       * constant. */
  897. {
  898.     int npat;
  899.     unsigned int P0;
  900.     
  901.     for (npat = 0; simpPatterns[npat][0] != STOP; npat++) {
  902.     unsigned int *pat;
  903.     pat = simpPatterns[npat];
  904.     if (matchPhrase(e, &pat, &P0) && matchPhrase(opnd1, &pat, &P0) && 
  905.         matchPhrase(opnd2, &pat, &P0)) {
  906.         return reduceExpr(npat+1, e, opnd1, opnd2);
  907.     }
  908.     }
  909.     return compressExpr(e, opnd1, opnd2);
  910. }
  911.  
  912. int
  913. matchPhrase(e, pat, P0)
  914.      union reloc_expr *e;
  915.      unsigned int **pat, *P0;
  916.      /* Return true iff e matches *pat, with *P0 as P register.  Sets *pat
  917.       * to after end of pattern on success.  May set *P0. */
  918. {
  919.     unsigned int cpat;
  920.  
  921.     for (cpat = **pat; ; (*pat)++, cpat = **pat, e++) {
  922.     if (cpat & SET_P0) *P0 = (*e).re_value;
  923.     if (! (cpat & DONT_CARE ||
  924.            cpat & EQ_P0 && e -> re_value == *P0 ||
  925.            cpat & ZERO  && e -> re_value == 0 ||
  926.            cpat & ONE && e -> re_value == 1 ||
  927.            e -> re_syl.re_op <= EO_SUB && cpat & 1 << e -> re_syl.re_op)) {
  928.         return FALSE;
  929.     }
  930.     if (cpat & STOP) {
  931.         (*pat)++; 
  932.         return TRUE;
  933.     }
  934.     }
  935. }
  936.     
  937. union reloc_expr *
  938. reduceExpr(n,  e, opnd1, opnd2)
  939.      int n;
  940.      union reloc_expr *e, *opnd1, *opnd2;
  941.      /* Destructively apply reduction n to operation with operator at
  942.       * e, and operands opnd1, opnd2.  Return result. */
  943. {
  944.     switch (n) {
  945.     case 1:     /* x +* const -> const +* x */
  946.     e = simpCanonLoadExpr(e, opnd2, opnd1);
  947.     return e;
  948.     case 2:     /* x - const -> -const + x */
  949.     EO_SET_SYL2(*e, EO_PLUS, 0);
  950.     opnd2[1].re_value = -opnd2[1].re_value;
  951.     e = simpCanonLoadExpr(e, opnd2, opnd1);
  952.     return e;
  953.     case 3:     /* const + sym -> sym (offset folded in) */
  954.     opnd2[1].re_value += opnd1[2].re_value;
  955.     return opnd2;
  956.     case 4:     /* sym - same sym -> difference of offsets */
  957.     EO_SET_SYL2(*opnd2, EO_INT, 0);
  958.     opnd1[1].re_value -= opnd2[1].re_value;
  959.     return opnd2;
  960.     case 5:    /* 0 * any -> 0 */
  961.     return opnd1;
  962.     case 6:    /* 0 + x -> x */
  963.     case 7:    /* 1 * x -> x */
  964.     return opnd2;
  965.     case 8:    /* 0 - x -> -x */
  966.     EO_SET_SYL2(*e, EO_MINUS, 0);
  967.     return simpCanonLoadExpr(e, opnd2, opnd2);
  968.     case 9:    /* - - x -> x */
  969.     return opnd1+1;
  970.     case 10:    /* x + -y -> x-y */
  971.     EO_SET_SYL2(*e, EO_SUB, 0);
  972.     return simpCanonLoadExpr(e, opnd1, opnd2+1);
  973.     case 11:    /* -x + y -> y-x */
  974.     EO_SET_SYL2(*e, EO_SUB, 0);
  975.     return simpCanonLoadExpr(e, opnd2, opnd1+1);
  976.     case 12:    /* x - -y -> x+y */
  977.     EO_SET_SYL2(*e, EO_PLUS, 0);
  978.     return simpCanonLoadExpr(e, opnd1, opnd2+1);
  979.     default:
  980.     InternalError;      /*NOTREACHED*/
  981.     }
  982. }
  983.  
  984. union reloc_expr *
  985. compressExpr(e, opnd1, opnd2)
  986.      union reloc_expr *e, *opnd1, *opnd2;
  987.      /* Return expression with operator from e and operands opnd1 and
  988.       * opnd2, compressed to contiguous storage in place.  It is
  989.       * assumed that all space from the first byte occupied by the
  990.       * arguments to the last is available, and that e is first. */
  991. {
  992.     if (e -> re_syl.re_op == EO_MINUS || e -> re_syl.re_op == EO_COMP) {
  993.     (void) bcopy((char *) opnd1, (char *) (e + 1), exprLength(opnd1));
  994.     return e;
  995.     }
  996.     else {
  997.     union reloc_expr *temp[MAXEXPRSYLS];
  998.     int len1 = exprLength(opnd1);
  999.     int len2 = exprLength(opnd2);
  1000.  
  1001.     if (len2 > MAXEXPRSYLS) {
  1002.         ErrorMsg  "Expression too long." EndMsg;
  1003.         exit(1);
  1004.         /*NOTREACHED*/
  1005.     }
  1006.     bcopy((char *) opnd2, (char *) temp, len2*sizeof(union reloc_expr));
  1007.     bcopy((char *) opnd1, (char *) (e+1), len1*sizeof(union reloc_expr));
  1008.     bcopy((char *) temp, (char *) (e+len1+1), 
  1009.           len2*sizeof(union reloc_expr));
  1010.     return e;
  1011.     }
  1012. }
  1013.  
  1014.         /* Relocation and symbol evaluation */
  1015.  
  1016. unsigned char *
  1017. relocSegmentToPntr(segment, file)
  1018.      unsigned int segment, file;
  1019.      /* Return pointer to given segment (an r_segment, indicated by RP_TEXT0, 
  1020.       * etc.) from given file, so that adding a byte offset gives address of 
  1021.       * quantity to relocate.  (In the case that segment = RP_SYMBOLS, the 
  1022.       * offset of the n_value field in the record is added in.) */
  1023. {
  1024.     switch (segment) {
  1025.     case RP_TEXT0:
  1026.     return (unsigned char *) fileText[file];
  1027.     case RP_DATA0:
  1028.     return (unsigned char *) fileData[file];
  1029.     case RP_SDATA0:
  1030.     return (unsigned char *) fileSData[file];
  1031.     case RP_SYMBOLS:
  1032.     return (unsigned char *) &(fileDefns[file] -> n_value);
  1033.     default:
  1034.     {
  1035.         struct nlist *sym = fileDefns[file] + segment - RP_SEG0;
  1036.         int stype = sym -> n_type & N_TYPE;
  1037.         if (stype == N_TEXT) 
  1038.         return  ((unsigned char *) fileText[file]) 
  1039.               + sym -> n_value - (int) fileTextAddr[file];
  1040.         else if (stype == N_DATA)
  1041.         return  ((unsigned char *) fileData[file]) 
  1042.               + sym -> n_value - (int) fileDataAddr[file];
  1043.         else if (stype == N_SDATA)
  1044.         return ((unsigned char *) fileSData[file])
  1045.               + sym -> n_value - (int) fileSDataAddr[file];
  1046.         else {
  1047.         FormatError;     /*NOTREACHED*/
  1048.         }
  1049.     }
  1050.     }
  1051. }
  1052.  
  1053. bool
  1054. valueFits(V, L)
  1055.      unsigned int V,L;
  1056.      /* Return true iff V, interpreted as a signed 32-bit quantity, is
  1057.       * acceptable for a signed field of size indicated by L (one of
  1058.       * RP_LOW8, ...).
  1059.       */
  1060. {
  1061.     /* The following looks like an odd test, but V is an
  1062.      * unsigned quantity that will be interpreted as signed.
  1063.      */
  1064.     return (V <= maxMap[L] || V >= minMap[L]);
  1065. }
  1066.  
  1067. void
  1068. fitError(file, segment, offset, value, length)
  1069.      unsigned int file, segment, offset, value, length;
  1070. {
  1071.     char segmentNameBuffer[20];
  1072.     char *segmentId;
  1073.  
  1074.     switch (segment) {
  1075.     case RP_TEXT0:
  1076.     segmentId = "text segment";
  1077.     break;
  1078.     case RP_DATA0:
  1079.     segmentId = "private data segment";
  1080.     break;
  1081.     case RP_SDATA0:
  1082.     segmentId = "shared data segment";
  1083.     break;
  1084.     default:
  1085.     segmentId = segmentNameBuffer;
  1086.     (void) strcpy(segmentNameBuffer, "extra segment 0");
  1087.     segmentNameBuffer[strlen(segmentNameBuffer)-1] += segment - RP_SEG0;
  1088.     break;
  1089.     }    
  1090.  
  1091.     ErrorMsg "%s: Value 0x%X does not fit in %d-bit field\n\tat offset 0x%X in %s.",
  1092.          fileName[file], value, lengthMap[length], offset, segmentId
  1093.     EndMsg;
  1094. }
  1095.  
  1096. void
  1097. insertVal(file, segment, offset, length, val)
  1098.      unsigned int file, segment, offset;
  1099.      unsigned int length, val;
  1100.      /* Insert val in bits indicated by length starting at offset from
  1101.       * given segment in given object file.  Length is RP_LOW8, etc.
  1102.       * Address to be modified must be divisible by 4, except for
  1103.       * RP_LOW8 and RP_LOW16, and must be divisible by 2 for RP_LOW16.
  1104.       * Produces warning messages if val is too large for field; val
  1105.       * is usually assumed to be signed for this purpose.  However,
  1106.       * RP_LOW28 is a special case.  There, val is treated as an
  1107.       * intra- segment word address, and is checked for agreement with
  1108.       * the eventual load-time address of the modified memory.
  1109.       */
  1110. {
  1111.     unsigned int
  1112.     byte = offset & 0x3,
  1113.     *word = 
  1114.         (unsigned int *)
  1115.               (relocSegmentToPntr(segment, file) + (offset & ~0x3)),
  1116.     bit = byte*8,
  1117.         realLoc = segmentOffsetToNewAddr(segment,file,offset);
  1118.     
  1119.     if (length == RP_LOW28) {
  1120.     if (((realLoc>>2 ^ val) & 0xf0000000) != 0) {
  1121.         ErrorMsg "Intersegment call or jump at %X.", realLoc EndMsg;
  1122.     }
  1123.     val &= 0x0fffffff;
  1124.     }
  1125.     else
  1126.     if (!valueFits(val, length))
  1127.         fitError(file, segment, offset, val, length);
  1128.     switch (length) {
  1129.     case RP_LOW8:
  1130.     *word = *word & (~(0xff << bit)) | (val & 0xff) << bit;
  1131.     break;
  1132.     case RP_LOW16:
  1133.     if (byte & 0x1) {
  1134.         FormatError;     /*NOTREACHED*/
  1135.     }
  1136.     *word = *word & (~(0xffff << bit)) | (val & 0xffff) << bit;
  1137.     break;
  1138.     case RP_LOW9:
  1139.     case RP_LOW14:
  1140.     case RP_LOW28:
  1141.     if (byte & 0x3) {
  1142.         FormatError;     /*NOTREACHED*/
  1143.     }
  1144.     *word =   *word & ~lengthBitMask[length] | val & lengthBitMask[length];
  1145.     break;
  1146.     case RP_SCONS:
  1147.     if (byte & 0x3) {
  1148.         FormatError;     /*NOTREACHED*/
  1149.     }
  1150.     *word =   *word & ~SCONSMASK | val & SCONSLOWMASK
  1151.             | val << (SCONSHIGHPOSN-SCONSLOWLEN) & SCONSHIGHMASK;
  1152.     break;
  1153.     case RP_32:
  1154.     *word = val;
  1155.     break;
  1156.     default:
  1157.     FormatError;     /*NOTREACHED*/
  1158.     }
  1159. }
  1160.  
  1161. unsigned int
  1162. extractVal(file, segment, offset, length)
  1163.      unsigned int file, segment, offset, length;
  1164.      /* Extract value in bits indicated by length starting at given
  1165.       * offset in given segment of given object file. Length is
  1166.       * RP_LOW8, etc.  Address must be divisible by 4. */
  1167. {
  1168.     unsigned int *word = 
  1169.     (unsigned int *) (relocSegmentToPntr(segment, file) + (offset & ~0x3));
  1170.     unsigned int byte = offset & 0x3;
  1171.     unsigned int bit = 8*byte;
  1172.  
  1173.     switch (length) {
  1174.     case RP_LOW8:
  1175.         return (*word & 0xff << bit) >> bit;
  1176.     case RP_LOW16:
  1177.     if (byte & 0x1) {
  1178.         FormatError;     /*NOTREACHED*/
  1179.     }
  1180.     return (*word  &  0xffff << bit) >> bit;
  1181.     case RP_LOW9:
  1182.     case RP_LOW14:
  1183.     case RP_LOW28:
  1184.     if (byte & 0x3) {
  1185.         FormatError;     /*NOTREACHED*/
  1186.     }
  1187.     return *word & lengthBitMask[length];
  1188.     case RP_SCONS:
  1189.     if (byte & 0x3) {
  1190.         FormatError;     /*NOTREACHED*/
  1191.     }
  1192.     return *word & SCONSLOWMASK |
  1193.         (*word & SCONSHIGHMASK) >> (SCONSHIGHPOSN-SCONSLOWLEN);
  1194.     case RP_32:
  1195.     return *word;
  1196.     default:
  1197.     FormatError;     /*NOTREACHED*/
  1198.     }
  1199. }
  1200.  
  1201.  
  1202. void
  1203. setLoc(segment, offset, file, length, wordp, val)
  1204.      unsigned int segment, offset, file, length, wordp, val;
  1205.      /* Set data at given offset from given segment (RP_TEXT0, etc.) in given 
  1206.       * file to val.  Length (RP_LOW8, etc.) indicates bits to change.  
  1207.       * Wordp is 1 if val is to be divided by word length, else 0. 
  1208.       * length == RP_LOW28 is a special case: val is first checked to
  1209.       * make sure it is in the same segment as the modified address,
  1210.       * and modified to make it legal.
  1211.       */
  1212. {
  1213.     if (wordp == 1) 
  1214.     val =
  1215.         (length == RP_LOW28) 
  1216.         ? val >> 2 
  1217.         : (unsigned int) (((int) val) >> 2);
  1218.  
  1219.     insertVal(file, segment, offset, length, val);
  1220. }
  1221.  
  1222. void
  1223. incrLoc(segment, offset, file, length, wordp, val)
  1224.      unsigned int segment, offset, file, length, wordp, val;
  1225.      /* As for setLoc above, but increment the location. */
  1226. {
  1227.     if (wordp == 1) 
  1228.     val =
  1229.         (length == RP_LOW28) 
  1230.         ? val >> 2 
  1231.         : (unsigned int) (((int) val) >> 2);
  1232.  
  1233.     insertVal(file, segment, offset, length,
  1234.           val + extractVal(file, segment, offset, length));
  1235. }
  1236.  
  1237. bool
  1238. evalReloc(reloc, file, keep)
  1239.      struct relocation_info *reloc;
  1240.      unsigned int file;
  1241.      bool keep;
  1242.      /* Check relocation item reloc from file number file.  If possible, 
  1243.       * perform indicated relocation, and set r_extra to indicate no further 
  1244.       * work needed.  If keep, then set reloc and its attendant expression (if
  1245.       * any) to most simplified form possible.  Set r_extra bits to RELOC_DONE
  1246.       * if relocation item should be kept and no further work is needed, 
  1247.       * RELOC_EXCLUDE if relocation item is no longer needed, and 0 otherwise.
  1248.       * Returns FALSE if no changes made to symbol table, otherwise TRUE.
  1249.       */
  1250. {
  1251.     unsigned int targetSeg, targetAddr, targetLength, targetWord;
  1252.     int symChanged;
  1253.  
  1254.     if (reloc -> r_extra != 0) return FALSE;
  1255.     targetSeg =     reloc -> r_segment;
  1256.     targetAddr =    reloc -> r_address;
  1257.     targetLength =  reloc -> r_length;
  1258.     targetWord =    reloc -> r_word;
  1259.     symChanged =    targetSeg == RP_SYMBOLS;  /* Initial guess */
  1260.  
  1261.     switch (reloc -> r_reltype) {
  1262.     case RP_RSEG:
  1263.     incrLoc(targetSeg, targetAddr, file, targetLength, targetWord,
  1264.         fileDelta[file][reloc -> r_expr]);
  1265.     reloc -> r_extra = RELOC_DONE;
  1266.     break;
  1267.     case RP_RSYM:
  1268.     {
  1269.         unsigned int realFile;
  1270.         struct nlist *sym;
  1271.  
  1272.         realSym(fileDefns[file] + reloc -> r_expr, file, &sym, &realFile);
  1273.  
  1274.         switch (sym -> n_type & N_TYPE) {
  1275.         case N_UNDF:
  1276.         case N_COMM:
  1277.         case N_SCOMM:
  1278.         symChanged = FALSE;
  1279.         break;
  1280.         case N_ABS:
  1281.         incrLoc(targetSeg, targetAddr, file, targetLength, targetWord,
  1282.             (unsigned int) sym -> n_value);
  1283.         reloc -> r_extra = RELOC_EXCLUDE;
  1284.         break;
  1285.         case N_TEXT:
  1286.         case N_DATA:
  1287.         case N_BSS:
  1288.         case N_SDATA:
  1289.         case N_SBSS:
  1290.         reloc -> r_expr = sym -> n_type & N_TYPE;
  1291.         incrLoc(targetSeg, targetAddr, file, targetLength, targetWord,
  1292.             (unsigned int) sym -> n_value);
  1293.         reloc -> r_reltype = RP_RSEG;
  1294.         reloc -> r_extra = RELOC_DONE;
  1295.         break;
  1296.         case N_EXPR:
  1297.         incrLoc(targetSeg, targetAddr, file, targetLength, targetWord,
  1298.             (unsigned int) sym -> n_value);
  1299.         reloc -> r_extra = RELOC_DONE;
  1300.         break;
  1301.         default:
  1302.         FormatError;     /*NOTREACHED*/
  1303.         }
  1304.     }
  1305.     break;
  1306.     case RP_REXP:
  1307.     {
  1308.         bool defined;
  1309.         unsigned int v;
  1310.         v = evalLoadExpr(fileRelocExprs[file] + 
  1311.                     (reloc -> r_expr / sizeof(union reloc_expr)),
  1312.                  file, &defined);
  1313.         if (defined) {
  1314.         setLoc(targetSeg, targetAddr, file, targetLength, targetWord,
  1315.                v);
  1316.         reloc -> r_extra = RELOC_DONE;
  1317.         if (keep) {
  1318.             union reloc_expr *e;
  1319.             int op;
  1320.  
  1321.             e = simpLoadExpr(BINCR(fileRelocExprs[file], 
  1322.                        reloc -> r_expr, union reloc_expr),
  1323.                      file);
  1324.             reloc -> r_expr = BDIFF(e, fileRelocExprs[file]);
  1325.  
  1326.             op = e -> re_syl.re_op;
  1327.             switch (op) {
  1328.             case EO_INT:
  1329.             reloc -> r_extra = RELOC_EXCLUDE;
  1330.             break;
  1331.             case EO_TEXT:
  1332.             case EO_DATA:
  1333.             case EO_BSS:
  1334.             case EO_SDATA:
  1335.             case EO_SBSS:
  1336.             reloc -> r_reltype = RP_RSEG;
  1337.             reloc -> r_expr = 
  1338.                 op == EO_TEXT ? N_TEXT :
  1339.                 op == EO_DATA ? N_DATA :
  1340.                 op == EO_BSS ? N_BSS :
  1341.                 op == EO_SDATA ? N_SDATA :
  1342.                 /* else */      N_SBSS;
  1343.             break;
  1344.             default:
  1345.             break;
  1346.             }
  1347.         }
  1348.         }
  1349.         else symChanged = FALSE;
  1350.     }
  1351.     break;
  1352.     default:
  1353.     FormatError;     /*NOTREACHED*/
  1354.     }
  1355.     if (symChanged) {
  1356.     struct nlist *sym = 
  1357.         (struct nlist *) (((char *) fileDefns[file]) + reloc -> r_address);
  1358.     int newtype;
  1359.     if (sym -> n_type & N_STAB)
  1360.         symChanged = FALSE;
  1361.     if (reloc -> r_extra == RELOC_EXCLUDE) {
  1362.         if (sym -> n_type & N_STAB) {
  1363.         newtype = N_UNDF;    /* Is this needed ? */
  1364.         }
  1365.         else {
  1366.         newtype = N_ABS;
  1367.         }
  1368.     }
  1369.     else if (reloc -> r_reltype == RP_RSEG) {
  1370.         reloc -> r_extra = RELOC_EXCLUDE;
  1371.         newtype = reloc -> r_expr;
  1372.     }
  1373.     else {
  1374.         newtype = N_EXPR;
  1375.     }
  1376.     sym -> n_type = (sym -> n_type & ~N_TYPE) | newtype;
  1377.     }
  1378.     if (reloc -> r_extra == RELOC_DONE && !keep) 
  1379.     reloc -> r_extra = RELOC_EXCLUDE;
  1380.     return symChanged;
  1381. }
  1382.     
  1383. void
  1384. relocateAll()
  1385.      /* Process all relocation information, and simplify all expressions as 
  1386.       * much as possible if keep.  Assumes all symbols are interned. 
  1387.       * Resolved relocations are marked RELOC_EXCLUDE if they are 
  1388.       * unnecessary. Common is allocated, if switches indicate. */
  1389. {
  1390.     int numUndefExprs;        /* Expression-defined symbols of type N_UNDF 
  1391.                  * in current pass. */
  1392.     int moreToDo;        /* False as long as no changes are made to 
  1393.                  * symbol table in current pass. */
  1394.     unsigned int file;
  1395.  
  1396.     relocateSymbols();
  1397.     if (!rSwitch || dSwitch) 
  1398.     resolveCommon();
  1399.     if (!rSwitch && baseFileName == NULL) 
  1400.     computeEnds();
  1401.     relocateExprs();
  1402.  
  1403.     do {
  1404.     moreToDo = FALSE;
  1405.     numUndefExprs = 0;
  1406.  
  1407.     for (file = 0; file < numFiles; file++) {
  1408.  
  1409.         struct relocation_info
  1410.         *reloc,
  1411.         *last =  (struct relocation_info *) 
  1412.                       ((char *) fileRelocs[file] + 
  1413.                    fileHeader[file].a_rsize);
  1414.  
  1415.         for (reloc = fileRelocs[file]; reloc != last; reloc++) {
  1416.         if (evalReloc(reloc, file, rSwitch) && numUndefExprs > 0)
  1417.             moreToDo = TRUE;
  1418.         if (reloc -> r_extra != 0) numUndefExprs++;
  1419.         }
  1420.     }
  1421.     } while (moreToDo);
  1422. }    
  1423.  
  1424.             /* Reading object files */
  1425.  
  1426. int
  1427. readOpenObjectFile(fd, size, name)
  1428.      int fd,size;
  1429.      char *name;
  1430.      /* Read object file of size bytes from file with descriptor fd as 
  1431.       * next file.  Return 0 if successful, and non-zero otherwise. 
  1432.       * Name is the file name for error messages. */
  1433. {
  1434.     char *contents;
  1435.     
  1436.     if (read(fd, (char *) &fileHeader[numFiles], sizeof(struct exec)) != 
  1437.         sizeof(struct exec)) {
  1438.     ErrorMsg "Unexpected EOF on file %s.", name EndMsg;
  1439.     return 1;
  1440.     }
  1441.     if (N_BADMAG(fileHeader[numFiles])) {
  1442.     ErrorMsg "Bad magic number on file %s.", name EndMsg;
  1443.     return 1;
  1444.     }
  1445.     else if (fileHeader[numFiles].a_magic != OMAGIC) {
  1446.     ErrorMsg "File %s cannot be relinked.", name 
  1447.         EndMsg;
  1448.     return 1;
  1449.     }
  1450.     
  1451.     contents = malloc((unsigned int) size - sizeof(struct exec));
  1452.     if (contents == NULL) {
  1453.     InsufficientSpace;
  1454.     }
  1455.     if (read(fd, contents, size - sizeof(struct exec)) != 
  1456.         size - sizeof(struct exec)) {
  1457.     ErrorMsg "Could not read file %s.", name EndMsg;
  1458.     return 1;
  1459.     }
  1460.  
  1461.     contents -= sizeof(struct exec);    /* Compensate for missing header. */
  1462.  
  1463.     fileText[numFiles] =    /* Works only for OMAGIC input. */
  1464.     (unsigned int *) (contents + N_TXTOFF(fileHeader[numFiles]));
  1465.     fileData[numFiles] =
  1466.     (unsigned int *) (contents + N_DATAOFF(fileHeader[numFiles]));
  1467.     fileSData[numFiles] = 
  1468.     (unsigned int *) (contents + N_SDATAOFF(fileHeader[numFiles]));
  1469.     fileDefns[numFiles] = 
  1470.     (struct nlist *) (contents + N_SYMOFF(fileHeader[numFiles]));
  1471.     fileRelocs[numFiles] = 
  1472.     (struct relocation_info *) 
  1473.         (contents + N_RELOCOFF(fileHeader[numFiles]));
  1474.     fileRelocExprs[numFiles] = 
  1475.     (union reloc_expr *) (contents + N_RELOCOFF(fileHeader[numFiles]) + 
  1476.                    fileHeader[numFiles].a_rsize);
  1477.     fileStrings[numFiles] = contents + N_STROFF(fileHeader[numFiles]);
  1478.  
  1479.     return 0;
  1480. }
  1481.             /* Library Support */
  1482.  
  1483. bool
  1484. isLibraryFile(fd)
  1485.      int fd;
  1486.      /* Given that fd is a file descriptor positioned at the beginning of
  1487.       * a file, returns TRUE iff fd appears to be the descriptor of a
  1488.       * library file.  Positions fd to beginning.
  1489.       */
  1490. {
  1491.     char arMagic[SARMAG+1];
  1492.     int len;
  1493.  
  1494.     arMagic[SARMAG] = '\0';
  1495.     len = read(fd, arMagic, SARMAG);
  1496.     if (lseek(fd, (long) 0, L_SET) == -1) return FALSE;
  1497.     return (len == SARMAG && strcmp(arMagic, ARMAG) == 0);
  1498. }
  1499.     
  1500. int
  1501. searchLibList(name, dirList)
  1502.      char *name;
  1503.      char *dirList[];
  1504.      /* Search for library with given name in directories dirList
  1505.       * (which is terminated by a NULL).  Return file descriptor for open 
  1506.       * library, or -1.  */
  1507. {
  1508.     char **dir;
  1509.     int fd;
  1510.     
  1511.     for (dir = dirList, fd = -1; *dir != NULL && fd == -1; dir++) {
  1512.     char fileName[MAXFILENAMESIZE+1];
  1513.     int len;
  1514.  
  1515.     fileName[MAXFILENAMESIZE] = '\0';
  1516.     (void) strncpy(fileName, *dir, MAXFILENAMESIZE+1);
  1517.     len = strlen(fileName);
  1518.     if (fileName[len-1] != '/') {
  1519.         (void) strncpy(fileName+len, "/", MAXFILENAMESIZE-len+1);
  1520.         len ++;
  1521.     }
  1522.     (void) strncpy(fileName+len, "lib", MAXFILENAMESIZE-len+1);
  1523.     len += 3;
  1524.     (void) strncpy(fileName + len, name, MAXFILENAMESIZE-len+1);
  1525.     len += strlen(name);
  1526.     (void) strncpy(fileName + len, ".a", MAXFILENAMESIZE-len+1);
  1527.  
  1528.     fd = open(fileName, O_RDONLY);
  1529.     }
  1530.  
  1531.     return fd;
  1532. }
  1533.         
  1534. int
  1535. openLibrary(name)
  1536.      char *name;
  1537.      /* Search for library file with given name.  Search for it in 
  1538.       * directories listed in -L options in dirList and in the standard 
  1539.       * library directories. Return fd of opened library file, or -1 if no 
  1540.       * openable file found. */
  1541. {
  1542.     int fd;
  1543.  
  1544.     fd = searchLibList(name, dirList);
  1545.     if (fd == -1)
  1546.     return searchLibList(name, standardLibs);
  1547.     else return fd;
  1548. }
  1549.  
  1550. void
  1551. resolveStrings(symTab, n, strings)
  1552.      struct ranlib symTab[];
  1553.      int n;
  1554.      char *strings;
  1555.      /* Change all ran_un entries in symTab[0..n-1] from indices into
  1556.       * strings to pointers into strings. */
  1557. {
  1558.     int i;
  1559.  
  1560.     for (i = 0; i < n; i++)
  1561.     symTab[i].ran_un.ran_name = strings + symTab[i].ran_un.ran_strx;
  1562. }
  1563.  
  1564. int
  1565. ranlibCompare(x,y)
  1566.      struct ranlib *x,*y;
  1567.      /* Returns 0 if name of *x == that of *y, -1 if *x's is less, 1 otherwise.
  1568.       */
  1569. {
  1570.     return strcmp(x -> ran_un.ran_name, y -> ran_un.ran_name);
  1571. }
  1572.  
  1573. int
  1574. indirectStrcmp(x,y)
  1575.      char **x,**y;
  1576. {
  1577.     return strcmp(*x, *y);
  1578. }
  1579.  
  1580. int
  1581. findResolvingFile(symTab, numSyms, name, file)
  1582.      struct ranlib symTab[];
  1583.      int numSyms;
  1584.      char **name;
  1585.      int *file;
  1586.      /* Find a symbol in symTab[0..numSyms-1] that is unresolved and return the
  1587.       * offset of the defining object file recorded for that symbol in symTab.
  1588.       * The entries in symTab must be sorted alphabetically, and must use 
  1589.       * the ran_name fields to point directly at strings. Return 0 
  1590.       * if no file.   If file found, set *name to point to the name of 
  1591.       * a symbol that caused the returned file to be found, and *file to
  1592.       * the index of an object file that references that name. */
  1593. {
  1594.     globalSymType *ref;
  1595.     struct ranlib *fileRef;
  1596.  
  1597.     for (ref = unresolvedSyms.nextUnresolved, fileRef = NULL; 
  1598.      fileRef == NULL && ref != &unresolvedSyms;
  1599.      ref = ref -> nextUnresolved) {
  1600.  
  1601.         struct ranlib target;
  1602.         target.ran_un.ran_name = *name = ref -> name;
  1603.         *file = ref -> file;
  1604.         fileRef = 
  1605.         (struct ranlib *) bsearch((char *) &target, (char *) symTab, 
  1606.                       (unsigned) numSyms, 
  1607.                       sizeof(struct ranlib),
  1608.                       ranlibCompare);
  1609.     }
  1610.     if (fileRef == NULL) return 0;
  1611.     else return fileRef -> ran_off;
  1612. }
  1613.  
  1614. void
  1615. readOpenLibraryFile(fd, name)
  1616.      int fd;
  1617.      char *name;
  1618.      /* Read library from file with descriptor fd as object files.
  1619.       * Name is the name of the library for error messages.  */
  1620. {
  1621.     struct ar_hdr SYMDEFHead;
  1622.     int symBytes, numObjs;
  1623.     struct ranlib *extSyms = NULL;
  1624.     int stringSpaceSize;
  1625.     char *stringSpace = NULL;
  1626.     
  1627.     if (lseek(fd, (long) SARMAG, L_SET) == -1 ||
  1628.     read(fd, (char *) &SYMDEFHead, sizeof(struct ar_hdr))
  1629.           != sizeof(struct ar_hdr) ||
  1630.     strncmp(SYMDEFHead.ar_fmag, ARFMAG, sizeof(SYMDEFHead.ar_fmag)) != 0 ||
  1631.     strncmp(SYMDEFHead.ar_name, "__.SYMDEF ", 10) != 0 ||
  1632.     read(fd, (char *) &symBytes, sizeof(symBytes)) != sizeof(symBytes))
  1633.         goto BadFormat;
  1634.  
  1635.     extSyms = (struct ranlib *) malloc((unsigned int) symBytes);
  1636.     if (extSyms == NULL) {
  1637.     InsufficientSpace
  1638.     }
  1639.     if (read(fd, (char *) extSyms, symBytes) != symBytes)
  1640.     goto BadFormat;
  1641.     numObjs = symBytes / sizeof(struct ranlib);
  1642.  
  1643.     if (read(fd, (char *) &stringSpaceSize, sizeof(stringSpaceSize)) != 
  1644.     sizeof(stringSpaceSize))
  1645.         goto BadFormat;
  1646.     stringSpace = malloc((unsigned int) stringSpaceSize);
  1647.     if (stringSpace == NULL) {
  1648.     InsufficientSpace;
  1649.     }
  1650.     if (read(fd, stringSpace, stringSpaceSize) != stringSpaceSize) 
  1651.     goto BadFormat;
  1652.  
  1653.     resolveStrings(extSyms, numObjs, stringSpace);
  1654.     qsort((char *) extSyms, numObjs, sizeof(struct ranlib), ranlibCompare);
  1655.  
  1656.     do {
  1657.     char *symName;
  1658.     int symFile;
  1659.     int fileOffset = 
  1660.         findResolvingFile(extSyms, numObjs, &symName, &symFile);
  1661.     struct ar_hdr objHeader;
  1662.     int size;
  1663.  
  1664.     if (fileOffset == 0) goto Finish;
  1665.  
  1666.     if ((int) lseek(fd, (long) fileOffset, L_SET) == -1 ||
  1667.         read(fd, (char *) &objHeader, sizeof(objHeader)) != 
  1668.             sizeof(objHeader) ||
  1669.         strncmp(objHeader.ar_fmag, ARFMAG, sizeof(objHeader.ar_fmag)) != 0)
  1670.             goto BadFormat;
  1671.     (void) sscanf(objHeader.ar_size, "%d", &size);
  1672.  
  1673.     fileName[numFiles] = malloc(sizeof(objHeader.ar_name)+1);
  1674.     (void) strncpy(fileName[numFiles], objHeader.ar_name, 
  1675.                sizeof(objHeader.ar_name));
  1676.     {
  1677.         char *s = fileName[numFiles] + sizeof(objHeader.ar_name) - 1;
  1678.         while (s != fileName[numFiles] && *s == ' ')
  1679.         s -= 1;
  1680.         s[1] = '\0';
  1681.     }
  1682.  
  1683.     if (wSwitch) {
  1684.         (void) printf("Library file %s loaded for %s referenced in %s.\n",
  1685.            fileName[numFiles], symName, fileName[symFile]);
  1686.     }
  1687.  
  1688.     if (readOpenObjectFile(fd, size, name) != 0)
  1689.         goto BadFormat;
  1690.     convertStringIndices(numFiles);
  1691.     internAllSyms(numFiles);
  1692.     numFiles += 1;
  1693.     } while (TRUE);
  1694.  
  1695.  BadFormat:
  1696.     ErrorMsg "Bad format on library file %s.", name EndMsg;
  1697.  
  1698.  Finish:
  1699.     (void) close(fd);
  1700.     if (extSyms != NULL) (void) free((char *) extSyms);
  1701.     if (stringSpace != NULL) (void) free(stringSpace);
  1702.     return;
  1703. }
  1704.  
  1705. void
  1706. setupForcedSyms()
  1707.      /* Set up a dummy file for symbols from -u options */
  1708. {
  1709.     (void) bzero((char *) &fileHeader[numFiles], sizeof (struct exec));
  1710.     fileHeader[numFiles].a_magic = OMAGIC;
  1711.     fileHeader[numFiles].a_syms = sizeof(struct nlist) * numForcedSyms;
  1712.  
  1713.     fileText[numFiles] = fileData[numFiles] = fileSData[numFiles] = NULL;
  1714.     fileRelocs[numFiles] = NULL;
  1715.     fileStrings[numFiles] = NULL;
  1716.     fileRelocExprs[numFiles] = NULL;
  1717.     fileName[numFiles] = NULL;
  1718.     fileDefns[numFiles] = forcedSyms;
  1719.  
  1720.     internAllSyms(numFiles);
  1721.  
  1722.     numFiles += 1;
  1723. }
  1724.  
  1725. void
  1726. setupBaseFile()
  1727.      /* "Load" a dummy file corresponding to the base file named in -A
  1728.       * option. */
  1729. {
  1730.     int fd = open(baseFileName, O_RDONLY);
  1731.     unsigned int size;    /* Size of base file */
  1732.  
  1733.     if (fd == -1) {
  1734.     ErrorMsg "Failed to open base file %s.", baseFileName EndMsg;
  1735.     exit(1);
  1736.     }
  1737.  
  1738.     { 
  1739.     struct stat stats;
  1740.     (void) fstat(fd, &stats);
  1741.     size = stats.st_size;
  1742.     }
  1743.  
  1744.     if (read(fd, (char *) &fileHeader[numFiles], sizeof(struct exec)) !=
  1745.     sizeof(struct exec)) {
  1746.     ErrorMsg "Unexpected EOF on file %s.", baseFileName EndMsg;
  1747.     exit(1);
  1748.     }
  1749.     if (fileHeader[numFiles].a_magic != ZMAGIC) {
  1750.     ErrorMsg "Base file has improper magic number." EndMsg;
  1751.     exit(1);
  1752.     }
  1753.     fileName[numFiles] = baseFileName;
  1754.     fileDefns[numFiles] = 
  1755.     (struct nlist *) malloc(size - (int) N_SYMOFF(fileHeader[numFiles]));
  1756.     if (fileDefns[numFiles] == NULL) {
  1757.     InsufficientSpace;
  1758.     }
  1759.     if (lseek(fd, (long) N_SYMOFF(fileHeader[numFiles]), L_SET) == -1
  1760.     || read(fd, (char *) fileDefns[numFiles], 
  1761.         size - N_SYMOFF(fileHeader[numFiles]) 
  1762.            != size - N_SYMOFF(fileHeader[numFiles]))) {
  1763.  
  1764.     ErrorMsg "Could not read symbols and strings of file %s.", baseFileName
  1765.         EndMsg;
  1766.     exit(1);
  1767.     }
  1768.     (void) close(fd);
  1769.  
  1770.     fileStrings[numFiles] = 
  1771.     (char *) fileDefns[numFiles]
  1772.         + N_STROFF(fileHeader[numFiles]) - N_SYMOFF(fileHeader[numFiles]);
  1773.     convertStringIndices(numFiles);
  1774.     internAllSyms(numFiles);
  1775.  
  1776.     if (!TtextSwitch) {
  1777.     globalSymType **rep = findSymbolEntry("_end");
  1778.     
  1779.     if (*rep != NULL && (*rep) -> sym -> n_type == (N_BSS | N_EXT)) 
  1780.         textStart = (*rep) -> sym -> n_value;
  1781.     else
  1782.         textStart = 
  1783.         N_BSSADDR(fileHeader[numFiles]) + 
  1784.             fileHeader[numFiles].a_bss;
  1785.     }
  1786.     
  1787.     if (!TsdataSwitch) {
  1788.     globalSymType **rep = findSymbolEntry("_end_s");
  1789.     
  1790.     TsdataSwitch = TRUE;    /* Implicit setting */
  1791.     if (*rep != NULL && (*rep) -> sym -> n_type == (N_SBSS | N_EXT))
  1792.         sdataStart = (*rep) -> sym -> n_value;
  1793.     else 
  1794.         sdataStart =
  1795.         N_SBSSADDR(fileHeader[numFiles]) + 
  1796.             fileHeader[numFiles].a_sbss;
  1797.     }
  1798.  
  1799.     fileText[numFiles] = fileData[numFiles] = fileSData[numFiles] = NULL;
  1800.     fileRelocs[numFiles] = NULL;
  1801.     fileRelocExprs[numFiles] = NULL;
  1802.     (void) bzero((char *) &fileHeader[numFiles], sizeof(struct exec));
  1803.  
  1804.     numFiles += 1;
  1805. }
  1806.  
  1807.             /* Computing relocated addresses */
  1808.  
  1809. void
  1810. computeRelocations()
  1811.      /* Set fileTextAddr, fileDataAddr, fileBssAddr, fileSDataAddr,
  1812.       * fileSBssAddr, and fileDelta from fileHeader, given the
  1813.       * output file's desired magic number and the desired starting address
  1814.       * of the first text segment.  */
  1815. {
  1816.     unsigned int nextAddr;
  1817.     int i;
  1818.     
  1819.     if (numFiles == 0) return;
  1820.  
  1821.     nextAddr = textStart;
  1822.     if (!ptSwitch) {
  1823.     for (i = 0; i < numFiles; i++) {
  1824.         fileTextAddr[i] = nextAddr;
  1825.         fileDelta[i][N_TEXT] = nextAddr - N_DEFENT(fileHeader[i]);
  1826.         nextAddr += REAL_TEXT_LENGTH(fileHeader[i]);
  1827.     }
  1828.     }
  1829.  
  1830.     if (!pdSwitch) {
  1831.     if (TdataSwitch) {
  1832.         nextAddr = dataStart;
  1833.     }
  1834.     else {
  1835.         nextAddr = DATA_ADDR(nextAddr, magic);
  1836.     }
  1837.     
  1838.     for (i = 0; i < numFiles; i++) {
  1839.         fileDataAddr[i] = nextAddr;
  1840.         fileDelta[i][N_DATA] = nextAddr - N_DATADDR(fileHeader[i]);
  1841.         nextAddr += fileHeader[i].a_data;
  1842.     }
  1843.     
  1844.     for (i = 0; i < numFiles; i++) {
  1845.         fileBssAddr[i] = nextAddr;
  1846.         fileDelta[i][N_BSS] = nextAddr - N_BSSADDR(fileHeader[i]);
  1847.         nextAddr += fileHeader[i].a_bss;
  1848.     }
  1849.     }
  1850.  
  1851.     if (TsdataSwitch) {
  1852.     nextAddr = sdataStart;
  1853.     }
  1854.     else
  1855.     nextAddr = N_SDATADDR(0);
  1856.  
  1857.     if (ptSwitch) {
  1858.     for (i = 0; i < numFiles; i++) {
  1859.         fileTextAddr[i] = nextAddr;
  1860.         fileDelta[i][N_TEXT] = nextAddr - N_DEFENT(fileHeader[i]);
  1861.         nextAddr += REAL_TEXT_LENGTH(fileHeader[i]);
  1862.     }
  1863.     }
  1864.     for (i = 0; i < numFiles; i++) {
  1865.     if (pdSwitch) {
  1866.         fileDataAddr[i] = nextAddr;
  1867.         fileDelta[i][N_DATA] = nextAddr - N_DATADDR(fileHeader[i]);
  1868.         nextAddr += fileHeader[i].a_data;
  1869.     }
  1870.     fileSDataAddr[i] = nextAddr;
  1871.     fileDelta[i][N_SDATA] = nextAddr - N_SDATADDR(fileHeader[i]);
  1872.     nextAddr += fileHeader[i].a_sdata;
  1873.     }
  1874.  
  1875.     for (i = 0; i < numFiles; i++) {
  1876.     if (pdSwitch) {
  1877.         fileBssAddr[i] = nextAddr;
  1878.         fileDelta[i][N_BSS] = nextAddr - N_BSSADDR(fileHeader[i]);
  1879.         nextAddr += fileHeader[i].a_bss;
  1880.     }
  1881.     fileSBssAddr[i] = nextAddr;
  1882.     fileDelta[i][N_SBSS] = nextAddr - N_SBSSADDR(fileHeader[i]);
  1883.     nextAddr += fileHeader[i].a_sbss;
  1884.     }
  1885. }
  1886.  
  1887. void
  1888. resolveCommon()
  1889.      /* Allocate uninitialized common allocated by .comm directives.
  1890.       * Change all outstanding N_COMM symbol entries to N_BSS or
  1891.       * N_SBSS global definitions or to external references to the
  1892.       * first such definition and expand bss regions of last file as
  1893.       * needed.  */
  1894. {
  1895.     unsigned int file;
  1896.  
  1897.     for (file = 0; file < numFiles; file++) {
  1898.     struct nlist *sym,
  1899.                  *last = BINCR(fileDefns[file],fileHeader[file].a_syms,
  1900.                    struct nlist);
  1901.  
  1902.     for (sym = fileDefns[file]; sym != last; sym++) {
  1903.         int type = sym -> n_type;
  1904.         int stype = type & N_TYPE;
  1905.         if ((type & N_STAB) == 0
  1906.         && (stype == N_COMM || stype == N_SCOMM)) {
  1907.  
  1908.         struct nlist *nSym;
  1909.         unsigned int outFile;
  1910.  
  1911.         realSym(sym, file, &nSym, &outFile);
  1912.         if (sym != nSym) {
  1913.             sym -> n_type = N_UNDF | N_EXT;
  1914.             sym -> n_value = 0;
  1915.         }
  1916.         else {
  1917.             int len = sym -> n_value;
  1918.  
  1919.             sym -> n_un.n_name = globalReferent(sym) -> name;
  1920.             if (stype == N_COMM && !pdSwitch) {
  1921.             sym -> n_type = N_BSS | N_EXT;
  1922.             sym -> n_value = 
  1923.                 fileBssAddr[numFiles-1] + 
  1924.                 fileHeader[numFiles-1].a_bss;
  1925.             fileHeader[numFiles-1].a_bss += len;
  1926.             }
  1927.             else {
  1928.             sym -> n_type = N_SBSS | N_EXT;
  1929.             sym -> n_value = 
  1930.                 fileSBssAddr[numFiles-1] + 
  1931.                 fileHeader[numFiles-1].a_sbss;
  1932.             fileHeader[numFiles-1].a_sbss += len;
  1933.             }            
  1934.         }
  1935.         }
  1936.     }
  1937.     }
  1938. }
  1939.         
  1940. void
  1941. relocateSymbols()
  1942.      /* Relocate all symbol definitions using fileDelta. */
  1943. {
  1944.     unsigned int file;
  1945.  
  1946.     for (file = 0; file < numFiles; file++) {
  1947.     struct nlist *sym,
  1948.                  *last = BINCR(fileDefns[file],fileHeader[file].a_syms,
  1949.                    struct nlist);
  1950.  
  1951.     for (sym = fileDefns[file]; sym != last; sym++) {
  1952.         switch (sym -> n_type & N_TYPE) {
  1953.         case N_TEXT:
  1954.         case N_DATA:
  1955.         case N_BSS:
  1956.         case N_SDATA:
  1957.         case N_SBSS:
  1958.         sym -> n_value += fileDelta[file][sym -> n_type & N_TYPE];
  1959.         break;
  1960.         default:
  1961.         break;
  1962.         }
  1963.     }
  1964.     }
  1965. }
  1966.  
  1967. void
  1968. defineSpecialSymbol(name, V, T)
  1969.      char *name;
  1970.      unsigned long V;
  1971.      unsigned int T;
  1972.      /* If the global symbol name is referenced, define its value to be 
  1973.       * V and its n_type to be T.  Report an error if it is already defined. */
  1974. {
  1975.     globalSymType **rep = findSymbolEntry(name);
  1976.     struct nlist *sym;
  1977.  
  1978.     if (*rep == NULL) return;
  1979.  
  1980.     sym = (*rep) -> sym;
  1981.     if ((sym -> n_type & N_TYPE) == N_UNDF) {
  1982.     sym -> n_un.n_name = name;
  1983.     sym -> n_type = T;
  1984.     sym -> n_value = V;
  1985.     if ((*rep) -> nextUnresolved != NULL) {
  1986.         (*rep) -> nextUnresolved -> lastUnresolved =
  1987.         (*rep) -> lastUnresolved;
  1988.         (*rep) -> lastUnresolved -> nextUnresolved =
  1989.         (*rep) -> nextUnresolved;
  1990.         (*rep) -> lastUnresolved = (*rep) -> nextUnresolved = NULL;
  1991.     }
  1992.     }
  1993.     else {
  1994.     ErrorMsg "Symbol %s should not be defined explicitly.", name EndMsg;
  1995.     }
  1996. }
  1997.  
  1998. void
  1999. computeEnds()
  2000.      /* Set values for whichever of _etext, _edata, _end, _edata_s, 
  2001.       * and _end_s are present. */
  2002. {
  2003.     int last = numFiles - 1;
  2004.  
  2005.     defineSpecialSymbol("_etext", 
  2006.             fileTextAddr[last]+REAL_TEXT_LENGTH(fileHeader[last]),
  2007.             N_TEXT | N_EXT);
  2008.  
  2009.     if (pdSwitch) {
  2010.     defineSpecialSymbol("_edata", 
  2011.                 fileSDataAddr[last] + fileHeader[last].a_sdata,
  2012.                 N_SDATA | N_EXT);
  2013.     defineSpecialSymbol("_end", 
  2014.                 fileSBssAddr[last] + fileHeader[last].a_sbss,
  2015.                 N_SBSS | N_EXT);
  2016.     }
  2017.     else {
  2018.     defineSpecialSymbol("_edata", 
  2019.                 fileDataAddr[last] + fileHeader[last].a_data,
  2020.                 N_DATA | N_EXT);
  2021.     defineSpecialSymbol("_end", 
  2022.                 fileBssAddr[last] + fileHeader[last].a_bss,
  2023.                 N_BSS | N_EXT);
  2024.     }
  2025.  
  2026.     defineSpecialSymbol("_edata_s", 
  2027.             fileSDataAddr[last] + fileHeader[last].a_sdata,
  2028.             N_SDATA | N_EXT);
  2029.     defineSpecialSymbol("_end_s", fileSBssAddr[last] + fileHeader[last].a_sbss,
  2030.             N_SBSS | N_EXT);
  2031. }    
  2032.  
  2033. void
  2034. relocateExprs()
  2035.      /* Relocate all reloc_expr syllables of types EO_TEXT, EO_DATA, and EO_BSS
  2036.       * according to fileDelta. */
  2037. {
  2038.     unsigned int file;
  2039.  
  2040.     for (file = 0; file < numFiles; file++) {
  2041.     struct relocation_info 
  2042.         *reloc,
  2043.         *last = BINCR(fileRelocs[file], fileHeader[file].a_rsize,
  2044.               struct relocation_info);
  2045.  
  2046.     for (reloc = fileRelocs[file]; reloc != last; reloc++) {
  2047.         if (reloc -> r_reltype == RP_REXP) {
  2048.         union reloc_expr *e, *laste;
  2049.         
  2050.         for (e = BINCR(fileRelocExprs[file], reloc -> r_expr, 
  2051.                    union reloc_expr),
  2052.              laste = e + exprLength(e);
  2053.              e != laste;
  2054.              e++) {
  2055.             switch (e -> re_syl.re_op) {
  2056.             case EO_TEXT:
  2057.             case EO_DATA:
  2058.             case EO_BSS:
  2059.             case EO_SDATA:
  2060.             case EO_SBSS:
  2061.             e[1].re_value += 
  2062.                 fileDelta[file][EOtoNmap[e -> re_syl.re_op]];
  2063.             e++;
  2064.             break;
  2065.             case EO_INT:
  2066.             case EO_SYM:
  2067.             e++;
  2068.             break;
  2069.             default:
  2070.             break;
  2071.             }
  2072.         }
  2073.         }
  2074.     }
  2075.     }
  2076. }
  2077.  
  2078. unsigned int
  2079. findEntry(name, textStart)
  2080.      char *name;
  2081.      unsigned int textStart;
  2082.      /* Return relocated address of symbol name, or textStart if it does not
  2083.       * exist.  
  2084.       */
  2085. {
  2086.     struct nlist sym;
  2087.     union reloc_expr e[2];
  2088.     bool defined;
  2089.     unsigned int val;
  2090.  
  2091.     if (name == NULL) return textStart;
  2092.     /* Dummy up a symbol and an expression to use with evalSym */
  2093.     fileDefns[numFiles] = &sym;
  2094.     sym.n_un.n_name = name;
  2095.     sym.n_type = N_UNDF | N_EXT;
  2096.     sym.n_other = sym.n_desc = sym.n_value = 0;
  2097.     internSym(&sym, numFiles);
  2098.     EO_SET_SYL2(e[0], EO_SYM, 0);
  2099.     e[1].re_value = 0;
  2100.  
  2101.     val = evalSym(e, numFiles, &defined);
  2102.     if (!defined) {
  2103.     ErrorMsg "Entry name %s not defined.", name EndMsg;
  2104.     return textStart;
  2105.     }
  2106.     else return val;
  2107. }
  2108.  
  2109.             /* Building combined object file */
  2110.  
  2111. void
  2112. markUsedSymbols()
  2113.      /* Set SYM_USED bits in n_others for all symbols that are used in
  2114.       * relocation data. Used after relocations are processed and
  2115.       * excluded. */
  2116. {
  2117.     unsigned int file;
  2118.  
  2119.     for (file = 0; file < numFiles; file++) {
  2120.     struct relocation_info 
  2121.         *reloc,
  2122.         *last = BINCR(fileRelocs[file], fileHeader[file].a_rsize, 
  2123.               struct relocation_info);
  2124.     for (reloc = fileRelocs[file]; reloc != last; reloc++) {
  2125.         if (reloc -> r_extra != RELOC_EXCLUDE) {
  2126.         if (reloc -> r_reltype == RP_RSYM) {
  2127.             unsigned int realFile;
  2128.             struct nlist *sym;
  2129.             realSym(fileDefns[file] + reloc -> r_expr, file, &sym,
  2130.                 &realFile);
  2131.             sym -> n_other |= SYM_USED;
  2132.         }
  2133.         else if (reloc -> r_reltype == RP_REXP) {
  2134.             union reloc_expr
  2135.             *e = BINCR(fileRelocExprs[file],reloc -> 
  2136.                         r_expr,union reloc_expr),
  2137.             *last = e + exprLength(e);
  2138.             while (e != last) {
  2139.             switch (e -> re_syl.re_op) {
  2140.             case EO_SYM:
  2141.                 {
  2142.                 unsigned int realFile;
  2143.                 struct nlist *sym;
  2144.  
  2145.                 realSym(fileDefns[file] + e -> re_syl.re_arg, 
  2146.                     file, &sym, &realFile);
  2147.                 sym -> n_other |= SYM_USED;
  2148.                 e++;
  2149.                 break;
  2150.                 }
  2151.             case EO_INT:
  2152.             case EO_TEXT:
  2153.             case EO_DATA:
  2154.             case EO_BSS:
  2155.             case EO_SDATA:
  2156.             case EO_SBSS:
  2157.                 e++;
  2158.                 break;
  2159.             default:
  2160.                 break;
  2161.             }
  2162.             e++;
  2163.             }
  2164.         }
  2165.         }
  2166.     }
  2167.     }
  2168. }
  2169.  
  2170. void
  2171. countAndMarkSymbols(numSyms, stringSize)
  2172.      unsigned int *numSyms, *stringSize;
  2173.      /* Mark all symbols that that are to be excluded from the final symbol
  2174.       * table by setting the SYM_EXCLUDE flag in their n_other fields.  
  2175.       * It is assumed that symbols are interned, relocation expressions 
  2176.       * simplified or resolved, and SYM_USED bits in n_other set.   Set 
  2177.       * *numSyms to number of symbols retained in final table, and *stringSize
  2178.       * to total space needed for the string table for these symbols.
  2179.       */
  2180. {
  2181.     unsigned int file;
  2182.     
  2183.     *stringSize = *numSyms = 0;
  2184.     for (file = 0; file < numFiles; file++) {
  2185.     struct nlist *sym,
  2186.                  *last = (struct nlist *) 
  2187.                       ((char *) fileDefns[file] 
  2188.                    + fileHeader[file].a_syms);
  2189.  
  2190.     for (sym = fileDefns[file]; sym != last; sym++) {
  2191.         unsigned int fullType = sym -> n_type,
  2192.                      type = fullType & (N_TYPE | N_STAB);
  2193.         if (type == N_UNDF || type == N_COMM || type == N_SCOMM) {
  2194.         struct nlist *Rsym;
  2195.         unsigned int temp;
  2196.         realSym(sym, file, &Rsym, &temp);
  2197.         if (sym != Rsym) {
  2198.             sym -> n_other |= SYM_EXCLUDE;
  2199.             continue;
  2200.         }
  2201.         }
  2202.         if (   !sSwitch && fullType & N_EXT && (fullType & N_STAB) == 0
  2203.         || !sSwitch && !xSwitch && !SSwitch && fullType & N_STAB
  2204.         || rSwitch && (fullType & N_STAB) == 0 
  2205.            && sym -> n_other & SYM_USED
  2206.            && (type == N_UNDF || type == N_COMM
  2207.                || type == N_SCOMM || type == N_EXPR)
  2208.         || !xSwitch && !sSwitch && (fullType & N_STAB) == 0
  2209.            && (sym -> n_un.n_name)[0] != '\0' 
  2210.            && (!XSwitch || (sym -> n_un.n_name)[0] != 'L')) {
  2211.         char *s = symName(sym);
  2212.         (*numSyms)++;
  2213.         if (s[0] != '\0')
  2214.             *stringSize += strlen(s)+1;
  2215.         }
  2216.         else 
  2217.         sym -> n_other |= SYM_EXCLUDE;
  2218.     }
  2219.     }
  2220.     if (*stringSize > 0) *stringSize += 1;  /* Account for initial "" */
  2221. }
  2222.  
  2223. void
  2224. createNewSymbolsAndStrings(symbols, strings, symbolsSize, stringsSize, 
  2225.                allResolved)
  2226.      struct nlist **symbols;
  2227.      char **strings;
  2228.      unsigned int *symbolsSize, *stringsSize;
  2229.      bool *allResolved;
  2230.      /* Create new symbol and string tables for output file. Set n_value field
  2231.       * of non-excluded symbols to their ordinal numbers in the new table. Set
  2232.       * *symbols to new symbol table, *strings to new string table. Put their
  2233.       * sizes in bytes in *symbolsSize and *stringsSize.  Sets *allResolved to
  2234.       * TRUE iff all used symbols' values have been resolved.  Produces error
  2235.       * messages on stderr for undefined symbols, unless wantReloc is TRUE. */
  2236. {
  2237.     unsigned int nsyms;
  2238.     unsigned int file;
  2239.     struct nlist *newSym;
  2240.     char *newStr;
  2241.  
  2242.     *allResolved = TRUE;
  2243.  
  2244.     markUsedSymbols();
  2245.     countAndMarkSymbols(&nsyms, stringsSize);
  2246.  
  2247.     if (!xSwitch && !rSwitch && !sSwitch && numFiles > 1) {
  2248.     for (file = 0; file < numFiles; file++) {
  2249.         if (fileName[file] != NULL) {
  2250.         (*stringsSize) += strlen(fileName[file]) + 1;
  2251.         nsyms++;
  2252.         }
  2253.     }
  2254.     }
  2255.  
  2256.     *symbolsSize = nsyms * sizeof(struct nlist);
  2257.  
  2258.     if (nsyms == 0) {
  2259.     *symbols = NULL;
  2260.     *strings = NULL;
  2261.     return;
  2262.     }
  2263.  
  2264.     *stringsSize += sizeof(int);
  2265.     *symbols = (struct nlist *) malloc(nsyms * sizeof(struct nlist));
  2266.     *strings = (char *) malloc(*stringsSize);
  2267.     if (*symbols == NULL || *strings == NULL) {
  2268.     InsufficientSpace;
  2269.     }
  2270.  
  2271.     * ((int *) *strings) = *stringsSize;
  2272.     newSym = *symbols;
  2273.     newStr = *strings + sizeof(int);
  2274.  
  2275.     for (file = 0; file < numFiles; file++) {
  2276.     struct nlist *sym, 
  2277.                  *last = (struct nlist *) 
  2278.                       ((char *) fileDefns[file]
  2279.                    + fileHeader[file].a_syms);
  2280.  
  2281.     if (!sSwitch && !xSwitch && !rSwitch && numFiles>1 
  2282.         && fileName[file] != NULL) {
  2283.         newSym -> n_un.n_strx = newStr - *strings;
  2284.         newSym -> n_type = N_TEXT;
  2285.         newSym -> n_value = fileTextAddr[file];
  2286.         newSym -> n_other = newSym -> n_desc = 0;
  2287.         (void) strcpy(newStr, fileName[file]);
  2288.         newStr += strlen(newStr)+1;
  2289.         newSym++;
  2290.     }
  2291.     
  2292.         for (sym = fileDefns[file]; sym != last; sym++) {
  2293.         char *name;
  2294.         int symSimpType = sym -> n_type & N_TYPE;
  2295.         int symRestType = sym -> n_type ^ symSimpType;
  2296.  
  2297.         if ((sym -> n_other & SYM_EXCLUDE) == 0) {
  2298.         *newSym = *sym;    /* Initialize */
  2299.         sym -> n_value = newSym - *symbols;   /* Forwarding index */
  2300.         }
  2301.  
  2302.         name = symName(sym);
  2303.  
  2304.         switch (symSimpType) {
  2305.         case N_UNDF:
  2306.         if (sym -> n_other & SYM_USED) {
  2307.             *allResolved = FALSE;
  2308.             if (!rSwitch) {
  2309.             ErrorMsg "%s undefined.", name EndMsg;
  2310.             }
  2311.         }
  2312.         break;
  2313.         case N_COMM:
  2314.         case N_SCOMM:
  2315.         if (sym -> n_other & SYM_USED) {
  2316.             *allResolved = FALSE;
  2317.         }
  2318.         if (pdSwitch) {
  2319.             newSym -> n_type = N_SCOMM | symRestType;
  2320.         }
  2321.         break;
  2322.         case N_TEXT:
  2323.         if (ptSwitch) {
  2324.             newSym -> n_type = N_SDATA | symRestType;
  2325.         }
  2326.         break;
  2327.         case N_DATA:
  2328.         if (pdSwitch) {
  2329.             newSym -> n_type = N_SDATA | symRestType;
  2330.         }
  2331.         break;
  2332.         case N_BSS:
  2333.         if (pdSwitch) {
  2334.             newSym -> n_type = N_SBSS | symRestType;
  2335.         }
  2336.         break;
  2337.         case N_EXPR:
  2338.         newSym -> n_type = N_UNDF | symRestType;
  2339.         break;
  2340.         default:
  2341.         break;
  2342.         }
  2343.  
  2344.         if (sym -> n_other & SYM_EXCLUDE) /* REJECT */
  2345.         continue;
  2346.         
  2347.         if (name[0] != '\0') {
  2348.         newSym -> n_un.n_strx = newStr - *strings;
  2349.         (void) strcpy(newStr, name);
  2350.         newStr += strlen(name)+1;
  2351.         }
  2352.         else newSym -> n_un.n_strx = 0;
  2353.         newSym -> n_other = 0;    /* Must be 0 in file */
  2354.  
  2355.         newSym++;
  2356.     }
  2357.     }
  2358. }
  2359.  
  2360. unsigned int
  2361. segmentOffsetToNewAddr(segment, file, offset)
  2362.      unsigned int segment, file, offset;
  2363.      /* Return relocated address of [given segment (an r_segment, indicated by 
  2364.       * RP_TEXT0,  etc.) from given file + offset].  */
  2365. {
  2366.     switch (segment) {
  2367.     case RP_TEXT0:
  2368.     return fileTextAddr[file] + offset;
  2369.     case RP_DATA0:
  2370.     return fileDataAddr[file] + offset;
  2371.     case RP_SDATA0:
  2372.     return fileSDataAddr[file] + offset;
  2373.     case RP_SYMBOLS:
  2374.     {
  2375.         struct nlist *sym = BINCR(fileDefns[file], offset, struct nlist);
  2376.         return sym -> n_value * sizeof(struct nlist);
  2377.     }
  2378.     default:
  2379.     {
  2380.         struct nlist *sym = fileDefns[file] + segment - RP_SEG0;
  2381.         return offset + sym -> n_value;
  2382.     }
  2383.     }
  2384. }
  2385.  
  2386. unsigned int
  2387. newSegmentAddr(segment)
  2388.      unsigned int segment;
  2389.      /* Return the address of given segment in new file, where segment must be
  2390.       * RP_TEXT0, RP_DATA0, RP_SDATA0. */
  2391. {
  2392.     switch (segment) {
  2393.     case RP_TEXT0:
  2394.     return fileTextAddr[0];
  2395.     case RP_DATA0:
  2396.     return fileDataAddr[0];
  2397.     case RP_SDATA0:
  2398.     if (ptSwitch) {
  2399.         return fileTextAddr[0];
  2400.     }
  2401.     else if (pdSwitch) {
  2402.         return fileDataAddr[0];
  2403.     }
  2404.     else {
  2405.         return fileSDataAddr[0];
  2406.     }
  2407.     case RP_BSS:
  2408.     return fileBssAddr[0];
  2409.     case RP_SBSS:
  2410.     if (pdSwitch) {
  2411.         return fileBssAddr[0];
  2412.     }
  2413.     else {
  2414.         return fileSBssAddr[0];
  2415.     }
  2416.     default:
  2417.     ErrorMsg "Internal error in newSegmentAddr." EndMsg;
  2418.     exit(1);
  2419.     }
  2420. }
  2421.  
  2422. void
  2423. relocSizes(relocsSize, relocExprsSize)
  2424.      unsigned int *relocsSize, *relocExprsSize;
  2425.      /* Set *relocsSize to total number of bytes required for relocation items
  2426.       * and *relocExprsSize to the total number of bytes required for load-time
  2427.       * expressions in final file. */
  2428. {
  2429.     unsigned int file;
  2430.  
  2431.     *relocsSize = 0; 
  2432.     *relocExprsSize = 0;
  2433.     for (file = 0; file < numFiles; file++) {
  2434.     struct relocation_info 
  2435.         *reloc,
  2436.         *last = (struct relocation_info *) 
  2437.                ((int) fileRelocs[file] + fileHeader[file].a_rsize);
  2438.  
  2439.     for (reloc = fileRelocs[file]; reloc != last; reloc++) {
  2440.         if (reloc -> r_extra != RELOC_EXCLUDE) {
  2441.         *relocsSize += 1;
  2442.         if (reloc -> r_reltype == RP_REXP)
  2443.             *relocExprsSize += 
  2444.             exprLength(BINCR(fileRelocExprs[file], reloc -> r_expr,
  2445.                      union reloc_expr));
  2446.         }
  2447.     }
  2448.     }
  2449.     *relocsSize *= sizeof(struct relocation_info);
  2450.     *relocExprsSize *= sizeof(union reloc_expr);
  2451. }
  2452.  
  2453. void
  2454. createNewRelocs(relocs, relocExprs, relocsSize, relocExprsSize)
  2455.      struct relocation_info **relocs;
  2456.      union reloc_expr **relocExprs;
  2457.      unsigned int *relocsSize, *relocExprsSize;
  2458.      /* Create new relocation data, putting address of relocation item list
  2459.       * in *relocs and its size in bytes in *relocsSize, and address of block
  2460.       * of relocation expressions in *relocExprs and its size in 
  2461.       * *relocExprsSize.  Assumes new symbols have already been built. 
  2462.       */ 
  2463. {
  2464.     unsigned int file;
  2465.     struct relocation_info *newReloc;
  2466.     union reloc_expr *newRelocExpr;
  2467.     
  2468.     relocSizes(relocsSize, relocExprsSize);
  2469.  
  2470.     if (*relocsSize > 0) {
  2471.     newReloc = *relocs = (struct relocation_info *) malloc(*relocsSize);
  2472.     if (*relocs == NULL) {
  2473.         InsufficientSpace;
  2474.         /*NOTREACHED*/
  2475.     }
  2476.     }
  2477.     if (*relocExprsSize > 0) {
  2478.     newRelocExpr = *relocExprs = 
  2479.         (union reloc_expr *) malloc(*relocExprsSize);
  2480.     if (*relocExprs == NULL) {
  2481.         InsufficientSpace;
  2482.         /*NOTREACHED*/
  2483.     }
  2484.     }
  2485.  
  2486.     for (file = 0; file < numFiles; file++) {
  2487.     struct relocation_info 
  2488.         *reloc,
  2489.         *last = BINCR(fileRelocs[file], fileHeader[file].a_rsize, 
  2490.               struct relocation_info);
  2491.  
  2492.     for (reloc = fileRelocs[file]; reloc != last; reloc++) {
  2493.         if (reloc -> r_extra != RELOC_EXCLUDE) {
  2494.         switch (reloc -> r_segment) {
  2495.         case RP_TEXT0:
  2496.         case RP_DATA0:
  2497.         case RP_SDATA0:
  2498.         case RP_SYMBOLS:
  2499.             newReloc -> r_segment = reloc -> r_segment;
  2500.             break;
  2501.         default:
  2502.             { 
  2503.             int stype = 
  2504.                fileDefns[file][reloc -> r_segment - RP_SEG0].n_type
  2505.                    & N_TYPE;
  2506.  
  2507.             newReloc -> r_segment = 
  2508.                 stype == N_TEXT ? RP_TEXT0:
  2509.                 stype == N_DATA ? RP_DATA0:
  2510.                 RP_SDATA0;
  2511.             break;
  2512.             }
  2513.         }
  2514.  
  2515.         if (ptSwitch && newReloc -> r_segment == RP_TEXT0
  2516.             || pdSwitch && newReloc -> r_segment == RP_DATA0) {
  2517.             newReloc -> r_segment = RP_SDATA0;
  2518.         }
  2519.  
  2520.         newReloc -> r_address = 
  2521.             segmentOffsetToNewAddr(reloc -> r_segment, file, 
  2522.                        reloc -> r_address)
  2523.             - (reloc -> r_segment == RP_SYMBOLS ? 0
  2524.                : newSegmentAddr(newReloc -> r_segment));
  2525.         
  2526.         switch (reloc -> r_reltype) {
  2527.         case RP_REXP:
  2528.             newReloc -> r_expr = 
  2529.             BDIFF(createNewRelocExpr(BINCR(fileRelocExprs[file], 
  2530.                                reloc -> r_expr,
  2531.                                union reloc_expr),
  2532.                          file, &newRelocExpr),
  2533.                   *relocExprs);
  2534.             break;
  2535.         case RP_RSYM:
  2536.             {
  2537.             struct nlist *sym;
  2538.             unsigned int realFile;
  2539.  
  2540.             realSym(fileDefns[file] + reloc -> r_expr, file,
  2541.                 &sym, &realFile);
  2542.             newReloc -> r_expr = sym -> n_value;
  2543.             }
  2544.             break;
  2545.         case RP_RSEG:
  2546.             if (ptSwitch && reloc -> r_expr == N_TEXT
  2547.             || pdSwitch && reloc -> r_expr == N_DATA) {
  2548.             newReloc -> r_expr = N_SDATA;
  2549.             }
  2550.             else if (pdSwitch && reloc -> r_expr == N_BSS) {
  2551.             newReloc -> r_expr = N_SBSS;
  2552.             }
  2553.             else {
  2554.             newReloc -> r_expr = reloc -> r_expr;
  2555.             }
  2556.             break;
  2557.         default:
  2558.             InternalError;
  2559.             /*NOTREACHED*/
  2560.         }            
  2561.             
  2562.         newReloc -> r_word = reloc -> r_word;
  2563.         newReloc -> r_reltype = reloc -> r_reltype;
  2564.         newReloc -> r_length = reloc -> r_length;
  2565.         newReloc -> r_extra = 0;
  2566.         newReloc++;
  2567.         }
  2568.     }
  2569.     }
  2570. }
  2571.  
  2572. union reloc_expr *
  2573. createNewRelocExpr(e, file, newExpr)
  2574.      union reloc_expr *e, **newExpr;
  2575.      unsigned int file;
  2576.      /* Move and convert e to *newExpr, incrementing *newExpr beyond end of
  2577.       * new expression.  Return address of new expression. */
  2578. {
  2579.     int len = exprLength(e);
  2580.     union reloc_expr *ret = *newExpr;
  2581.     int i;
  2582.     
  2583.     i = 0;
  2584.     while (i < len) {
  2585.     int re_op = e -> re_syl.re_op;
  2586.  
  2587.                 /* Adjust for publicized segments.  */
  2588.     if (re_op == EO_TEXT && ptSwitch
  2589.         || re_op == EO_DATA && pdSwitch 
  2590.         || re_op == EO_BSS && pdSwitch) {
  2591.         bool dummy;
  2592.         unsigned int newOffset =
  2593.         evalLoadExpr(e, file, &dummy) 
  2594.             - newSegmentAddr(re_op == EO_BSS ? RP_SBSS : RP_SDATA0);
  2595.         EO_SET_SYL(*e, re_op == EO_BSS ? EO_SBSS : EO_SDATA);
  2596.         e[1].re_value = newOffset;
  2597.     }
  2598.     
  2599.     switch (re_op) {
  2600.     case EO_TEXT:
  2601.     case EO_DATA:
  2602.     case EO_BSS:
  2603.     case EO_INT:
  2604.     case EO_SDATA:
  2605.     case EO_SBSS:
  2606.         (*newExpr)[0] = e[0];
  2607.         (*newExpr)[1] = e[1];
  2608.         *newExpr += 2;
  2609.         e += 2;
  2610.         i++;
  2611.         break;
  2612.     case EO_SYM: {
  2613.         struct nlist *sym = &fileDefns[file][e -> re_syl.re_arg];
  2614.         int outFile;
  2615.  
  2616.         if ((sym -> n_type) & N_EXT) 
  2617.         realSym(sym,file,&sym,&outFile);
  2618.         EO_SET_SYL2(**newExpr, EO_SYM, sym -> n_value);
  2619.         (*newExpr)[1] = e[1];
  2620.         *newExpr += 2;
  2621.         e += 2;
  2622.         i++;
  2623.         break;
  2624.     }
  2625.     default:
  2626.         *(*newExpr)++ = *e++;
  2627.         break;
  2628.     }
  2629.     i++;
  2630.     }
  2631.     return ret;
  2632. }
  2633.  
  2634. void
  2635. writeObjectFile(fd, entry,
  2636.         relocs, relocsSize, relocExprs, relocExprsSize,
  2637.         symbols, symbolsSize, strings, stringsSize)
  2638.      int fd;
  2639.      unsigned int entry;
  2640.      struct nlist *symbols;
  2641.      struct relocation_info *relocs;
  2642.      union reloc_expr *relocExprs;
  2643.      char *strings;
  2644.      unsigned int symbolsSize, relocsSize, relocExprsSize, stringsSize;
  2645.      /* Write the specified portions of the object file to file fd. */
  2646. {
  2647.     int i;
  2648.     struct exec header;
  2649.     unsigned int textPad, dataPad, sdataPad;
  2650.     char ZEROS[PAGSIZ];
  2651.  
  2652.     (void) bzero(ZEROS, PAGSIZ);
  2653.  
  2654.     (void) bzero((char *) &header, sizeof header);
  2655.     header.a_magic = magic;
  2656.     header.a_bytord = 0x01020304;   /* This isn't quite right yet. */
  2657.     header.a_syms = symbolsSize;
  2658.     header.a_entry = entry;
  2659.     header.a_rsize = relocsSize;
  2660.     header.a_expsize = relocExprsSize;
  2661.  
  2662.     for (i = 0; i < numFiles; i++) {
  2663.     if (ptSwitch)
  2664.         header.a_sdata += REAL_TEXT_LENGTH(fileHeader[i]);
  2665.     else
  2666.         header.a_text += REAL_TEXT_LENGTH(fileHeader[i]);
  2667.     }
  2668.  
  2669.     for (i = 0; i < numFiles; i++) {
  2670.     if (pdSwitch) {
  2671.         header.a_sdata += fileHeader[i].a_data;
  2672.         header.a_sbss  += fileHeader[i].a_bss;
  2673.     }
  2674.     else {
  2675.         header.a_data += fileHeader[i].a_data;
  2676.         header.a_bss  += fileHeader[i].a_bss;
  2677.     }
  2678.     header.a_sdata += fileHeader[i].a_sdata;
  2679.     header.a_sbss  += fileHeader[i].a_sbss;
  2680.     }
  2681.  
  2682.     if (magic == ZMAGIC) { /* Round up segment sizes and put part of 
  2683.                   bss segments in data segments */
  2684.     header.a_text += sizeof(struct exec);
  2685.     textPad = 
  2686.         ( - (header.a_text & (PAGSIZ - 1))) % PAGSIZ;
  2687.     header.a_text += textPad;
  2688.  
  2689.     dataPad = ( - (header.a_data & (PAGSIZ - 1))) % PAGSIZ;
  2690.     if (header.a_bss < dataPad) 
  2691.         header.a_bss = 0;
  2692.     else
  2693.         header.a_bss -= dataPad;
  2694.     header.a_data += dataPad;
  2695.  
  2696.     sdataPad = ( - (header.a_sdata & (PAGSIZ - 1))) % PAGSIZ;
  2697.     if (header.a_sbss < sdataPad) 
  2698.         header.a_sbss = 0;
  2699.     else
  2700.         header.a_sbss -= sdataPad;
  2701.     header.a_sdata += sdataPad;
  2702.     
  2703.     }
  2704.     else 
  2705.     textPad = dataPad = sdataPad = 0;
  2706.  
  2707. #   define writeSeg(addr, num) \
  2708.     { \
  2709.         if (num != 0) {\
  2710.         int bytes = (num); \
  2711.         if (bytes != write(fd, (char *) (addr), bytes)) { \
  2712.                 ErrorMsg "Write to output file failed." EndMsg; \
  2713.         exit(1); \
  2714.         } \
  2715.     } \
  2716.     }
  2717.  
  2718.     writeSeg(&header, sizeof(struct exec));
  2719.  
  2720.     if (!ptSwitch) {
  2721.     for (i = 0; i < numFiles; i++) {
  2722.         writeSeg(fileText[i], REAL_TEXT_LENGTH(fileHeader[i]));
  2723.     }
  2724.     }
  2725.     writeSeg(ZEROS, textPad);
  2726.  
  2727.     if (!pdSwitch) {
  2728.     for (i = 0; i < numFiles; i++) {
  2729.         writeSeg(fileData[i], fileHeader[i].a_data);
  2730.     }
  2731.     writeSeg(ZEROS, dataPad);
  2732.     }
  2733.  
  2734.     if (ptSwitch) {
  2735.     for (i = 0; i < numFiles; i++) {
  2736.         writeSeg(fileText[i], REAL_TEXT_LENGTH(fileHeader[i]));
  2737.     }
  2738.     }
  2739.     for (i = 0; i < numFiles; i++) {
  2740.     if (pdSwitch) {
  2741.         writeSeg(fileData[i], fileHeader[i].a_data);
  2742.     }
  2743.     writeSeg(fileSData[i], fileHeader[i].a_sdata);
  2744.     }
  2745.     writeSeg(ZEROS, sdataPad);
  2746.  
  2747.     writeSeg(relocs, header.a_rsize);
  2748.     writeSeg(relocExprs, header.a_expsize);
  2749.     writeSeg(symbols, header.a_syms);
  2750.     writeSeg(strings, stringsSize);
  2751.  
  2752. #   undef writeSeg
  2753. }
  2754.  
  2755. void
  2756. writeCombinedFile(fd)
  2757.      int fd;
  2758.      /* Assuming all files read in and symbol table interned, create the
  2759.       * new object file on file fd.  */
  2760. {
  2761.     int allResolved;
  2762.     struct nlist *symbols;
  2763.     char *strings;
  2764.     struct relocation_info *relocs;
  2765.     union reloc_expr *relocExprs;
  2766.     unsigned int symbolsSize, stringsSize, relocsSize, relocExprsSize;
  2767.     unsigned int entryPoint;
  2768.  
  2769.     computeRelocations();
  2770.     
  2771.     relocateAll();
  2772.     
  2773.     entryPoint = findEntry(entryName, fileTextAddr[0]);
  2774.  
  2775.     createNewSymbolsAndStrings(&symbols, &strings, &symbolsSize, &stringsSize,
  2776.                    &allResolved);
  2777.  
  2778.     if (sSwitch) {
  2779.     symbols = NULL;
  2780.     strings = NULL;
  2781.     symbolsSize = stringsSize = 0;
  2782.     }
  2783.  
  2784.     if (rSwitch) {
  2785.     createNewRelocs(&relocs, &relocExprs, &relocsSize, &relocExprsSize);
  2786.     }
  2787.     else {
  2788.     relocs = NULL;
  2789.     relocExprs = NULL;
  2790.     relocsSize = relocExprsSize = 0;
  2791.     }
  2792.  
  2793.     writeObjectFile(fd, entryPoint, relocs, relocsSize,
  2794.             relocExprs, relocExprsSize, symbols, symbolsSize,
  2795.             strings, stringsSize);
  2796.  
  2797.     if (allResolved && errorCount == 0) {
  2798.     struct stat stats;
  2799.     (void) fstat(fd, &stats);
  2800.     (void) fchmod(fd, (int) (stats.st_mode
  2801.                   | (stats.st_mode >> 2 & 
  2802.                  (S_IEXEC | S_IEXEC>>3 | S_IEXEC>>6))));
  2803.     }
  2804. }
  2805.  
  2806.             /* Main routine */
  2807.  
  2808. void
  2809. initTables()
  2810. {
  2811.     EOtoNmap[EO_TEXT] = N_TEXT; 
  2812.     EOtoNmap[EO_DATA] = N_DATA;
  2813.     EOtoNmap[EO_BSS] = N_BSS;
  2814.     EOtoNmap[EO_SDATA] = N_SDATA;
  2815.     EOtoNmap[EO_BSS] = N_SBSS;
  2816. }
  2817.  
  2818. int
  2819. processCommandLineArgs(n, argv)
  2820.      int n;
  2821.      char *argv[];
  2822.      /* Set command line arguments from the command line in argv with n
  2823.       * entries.  Does not process files, -l options.  Remaining entries
  2824.       * are compressed; their total number is returned. */
  2825. {
  2826.     int i;
  2827.     unsigned int numLSwitches = 0;
  2828.  
  2829.     numForcedSyms = numTracedSyms = 0;
  2830.     dSwitch = MSwitch = pdSwitch = ptSwitch = rSwitch = sSwitch = SSwitch = 
  2831.     tSwitch = wSwitch = xSwitch = XSwitch = FALSE;
  2832.     TtextSwitch = TdataSwitch = TsdataSwitch = FALSE;
  2833.     outFileName = NULL;
  2834.     magic = 0;
  2835.     entryName = NULL;
  2836.     baseFileName = NULL;
  2837.  
  2838.     for (i = 1; i < n; i++) {
  2839.     if (argv[i][0] == '-') {
  2840.         switch (argv[i][1]) {
  2841.         case 'A':
  2842.         if (magic != ZMAGIC && i+1 < n && baseFileName == NULL) {
  2843.             baseFileName = argv[i+1];
  2844.             argv[i] = argv[i+1] = NULL;
  2845.             magic == OMAGIC;
  2846.             i += 1;
  2847.         }
  2848.         else {
  2849.             ErrorMsg "Invalid -A option." EndMsg;
  2850.             exit(1);
  2851.         }
  2852.         break;
  2853.         case 'd':
  2854.         dSwitch = TRUE, argv[i] = NULL;
  2855.         break;
  2856.         case 'e':
  2857.         if (i+1 < n && entryName == NULL) {
  2858.             numForcedSyms += 1;
  2859.             entryName = argv[i+1];
  2860.             i += 1;
  2861.         }
  2862.         else {
  2863.             ErrorMsg "Invalid entry name."  EndMsg;
  2864.             exit(1);
  2865.         }
  2866.         break;
  2867.         case 'l':
  2868.         break;
  2869.         case 'L':
  2870.         numLSwitches += 1;
  2871.         break;
  2872.         case 'N':
  2873.         if (magic == 0) magic = OMAGIC;
  2874.         argv[i] = NULL;
  2875.         break;
  2876.         case 'o':
  2877.         if (i+1 < n && outFileName == NULL) {
  2878.             outFileName = argv[++i];
  2879.             argv[i-1] = argv[i] = NULL;
  2880.         }
  2881.         else {
  2882.             ErrorMsg "Invalid output file name."  EndMsg;
  2883.             exit(1);
  2884.         }
  2885.         break;
  2886.         case 'p':
  2887.         if (argv[i][2] == 't' || argv[i][2] == 'T')
  2888.             ptSwitch = TRUE;
  2889.         else
  2890.             pdSwitch = TRUE;
  2891.         argv[i] = NULL;
  2892.         break;
  2893.         case 'r':
  2894.         rSwitch = TRUE;
  2895.         argv[i] = NULL;
  2896.         break;
  2897.         case 's':
  2898.         sSwitch = TRUE;
  2899.         argv[i] = NULL;
  2900.         break;
  2901.         case 'S':
  2902.         SSwitch = TRUE;
  2903.         argv[i] = NULL;
  2904.         break;
  2905.         case 'T':
  2906.         {
  2907.           enum { TEXT, DATA, SDATA } region;
  2908.           char *hex;
  2909.  
  2910.           if (strncmp(argv[i], "-Ttext", 6) == 0) 
  2911.               region = TEXT, hex = argv[i] + 6, TtextSwitch = TRUE;
  2912.           else if (strncmp(argv[i], "-Tdata", 6) == 0) 
  2913.               region = DATA, hex = argv[i] + 6, TdataSwitch = TRUE;
  2914.           else if (strncmp(argv[i], "-Tsdata", 7) == 0) 
  2915.               region = SDATA, hex = argv[i] + 7, TsdataSwitch = TRUE;
  2916.           else region = TEXT, hex = argv[i] + 2, TtextSwitch = TRUE;
  2917.             
  2918.           if (*hex == '\0') {
  2919.               argv[i] = NULL;
  2920.               if (i+1 < n) 
  2921.               hex = argv[++i];
  2922.               else {
  2923.               ErrorMsg "Invalid -T argument." EndMsg;
  2924.               exit(1);
  2925.               }
  2926.           }
  2927.  
  2928.           if (hex[0] == '0' && hex[1] == 'x') hex += 2;
  2929.           (void) sscanf(hex, "%x", 
  2930.                 region == TEXT ? &textStart :
  2931.                 region == DATA ? &dataStart :
  2932.                 &sdataStart);
  2933.           argv[i] = NULL;
  2934.         }
  2935.         break;
  2936.         case 'u':
  2937.         numForcedSyms += 1;
  2938.         i += 1;
  2939.         break;
  2940.         case 'w':
  2941.         wSwitch = TRUE;
  2942.         argv[i] = NULL;
  2943.         break;
  2944.         case 'x':
  2945.         xSwitch = TRUE;
  2946.         argv[i] = NULL;
  2947.         break;
  2948.         case 'X':
  2949.         XSwitch = TRUE;    
  2950.         argv[i] = NULL;
  2951.         break;
  2952.         case 'y':
  2953.         numTracedSyms += 1;
  2954.         break;
  2955.         case 'z':
  2956.         if (magic == 0) magic = ZMAGIC;
  2957.         argv[i] = NULL;
  2958.         break;
  2959.         default:
  2960.         ErrorMsg "Unknown switch: %s.", argv[i] EndMsg;
  2961.         exit(1);
  2962.         break;
  2963.         }
  2964.     }
  2965.     }
  2966.  
  2967.     {
  2968.        char **nextLOption, **nextYOption; 
  2969.        struct nlist *nextuOption;
  2970.        nextLOption = dirList = 
  2971.        (char **) calloc(numLSwitches+1, sizeof(char *));
  2972.        nextYOption = tracedSyms = 
  2973.        (char **) calloc(numTracedSyms, sizeof(char *));
  2974.        nextuOption = forcedSyms = 
  2975.        (struct nlist *) calloc(numForcedSyms, sizeof(struct nlist));
  2976.        for (i = 1; i < n; i++) {
  2977.        if (argv[i] != NULL && argv[i][0] == '-') {
  2978.            switch (argv[i][1]) {
  2979.            default:
  2980.            break;
  2981.            case 'L':
  2982.            *nextLOption++ = argv[i]+2;
  2983.            argv[i] = NULL;
  2984.            break;
  2985.            case 'y':
  2986.            *nextYOption++ = argv[i]+2;
  2987.            argv[i] = NULL;
  2988.            break;
  2989.            case 'u':
  2990.            case 'e':
  2991.            i += 1;
  2992.            if (i >= n) {
  2993.                ErrorMsg "Invalid -u option." EndMsg;
  2994.                exit(1);
  2995.            }
  2996.            nextuOption -> n_un.n_name = argv[i];
  2997.            nextuOption -> n_type = N_EXT | N_UNDF;
  2998.            nextuOption -> n_value = 0;
  2999.            nextuOption -> n_desc = nextuOption -> n_other = 0;
  3000.            nextuOption++;
  3001.            argv[i] = argv[i-1] = NULL;
  3002.            break;
  3003.            }
  3004.        }
  3005.        }
  3006.        *nextLOption = NULL;
  3007.        qsort((char *) tracedSyms, (int) numTracedSyms, sizeof(char *),
  3008.          indirectStrcmp);
  3009.     }
  3010.  
  3011.     if (sSwitch) XSwitch = xSwitch = SSwitch = rSwitch = FALSE;
  3012.     if (SSwitch) XSwitch = xSwitch = FALSE;
  3013.     if (xSwitch) XSwitch = FALSE;
  3014.     if (rSwitch) magic = OMAGIC;
  3015.  
  3016.     if (magic == 0) 
  3017.     magic = (TtextSwitch || TdataSwitch || TsdataSwitch) ? OMAGIC : ZMAGIC;
  3018.     if (outFileName == NULL) outFileName = "a.out";
  3019.     if (! TtextSwitch) {
  3020.     aHeader.a_magic = magic;
  3021.     textStart = N_DEFENT(aHeader);
  3022.     }
  3023.  
  3024.     {
  3025.       int t,f;
  3026.  
  3027.       for (t = f = 1; f < n; f++)
  3028.       if (argv[f] != NULL) argv[t++] = argv[f];
  3029.       return t;
  3030.     }
  3031. }
  3032.  
  3033.  
  3034. main(argc, argv)
  3035.      int argc;
  3036.      char *argv[];
  3037. {
  3038.     int outFd;
  3039.     int i;
  3040.  
  3041.     unresolvedSyms.link = &unresolvedSyms;
  3042.     unresolvedSyms.nextUnresolved = &unresolvedSyms;
  3043.     
  3044.     errorCount = 0;
  3045.     programName = argv[0];
  3046.     initTables();
  3047.     argc = processCommandLineArgs(argc,argv);
  3048.  
  3049.     numFiles = 0;
  3050.     setupForcedSyms();
  3051.     if (baseFileName != NULL) 
  3052.     setupBaseFile();
  3053.     
  3054.     for (i = 1; i < argc; i++) {
  3055.     if (argv[i][0] == '-' && argv[i][1] == 'l') {
  3056.         int fd = openLibrary(argv[i]+2);
  3057.         if (fd == -1) {
  3058.         ErrorMsg
  3059.             "Failed to open library file %s.", argv[i]+2
  3060.             EndMsg;
  3061.         break;
  3062.         }
  3063.         readOpenLibraryFile(fd, argv[i]+2);
  3064.         (void) close(fd);
  3065.     }
  3066.     else if (argv[i][0] != '-') {
  3067.         int fd = open(argv[i], O_RDONLY);
  3068.         if (fd == -1) {
  3069.         ErrorMsg "Failed to open load file %s.", argv[i] EndMsg;
  3070.         exit(1);
  3071.         /*NOTREACHED*/
  3072.         }
  3073.         
  3074.         if (isLibraryFile(fd)) {
  3075.         readOpenLibraryFile(fd, argv[i]);
  3076.         }
  3077.         else {
  3078.         struct stat stats;
  3079.         (void) fstat(fd, &stats);
  3080.  
  3081.         fileName[numFiles] = argv[i];
  3082.  
  3083.         if (readOpenObjectFile(fd, stats.st_size, argv[i])
  3084.             != 0) 
  3085.                 exit(1);
  3086.         convertStringIndices(numFiles);
  3087.         internAllSyms(numFiles);
  3088.         numFiles++;
  3089.         }
  3090.         (void) close(fd);
  3091.     }
  3092.     }
  3093.     
  3094.     outFd = open(outFileName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  3095.     if (outFd == -1) {
  3096.     ErrorMsg "Could not open output file." EndMsg;
  3097.     exit(1);
  3098.     }
  3099.     
  3100.     writeCombinedFile(outFd);    
  3101.     (void) close(outFd);
  3102.  
  3103.     if (errorCount) 
  3104.     exit(1);
  3105.     else
  3106.     exit(0);
  3107. }
  3108.